Add support for compressed certificates (RFC8879)

* Compressed Certificate extension (server/client)
* Server certificates (send/receive)
* Client certificate (send/receive)

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18186)
This commit is contained in:
Todd Short 2021-08-09 16:56:50 -04:00 committed by Todd Short
parent 59d21298df
commit b67cb09f8d
57 changed files with 2661 additions and 92 deletions

View File

@ -24,6 +24,11 @@ OpenSSL 3.2
### Changes between 3.0 and 3.2 [xx XXX xxxx]
* Add support for certificate compression (RFC8879), including
library support for Brotli and Zstandard compression.
*Todd Short*
* Add the ability to add custom attributes to PKCS12 files. Add a new API
PKCS12_create_ex2, identical to the existing PKCS12_create_ex but allows
for a user specified callback and optional argument.

View File

@ -21,6 +21,8 @@ OpenSSL 3.2
### Major changes between OpenSSL 3.0 and OpenSSL 3.2 [under development]
* Added support for certificate compression (RFC8879), including
library support for Brotli and Zstandard compression.
* Subject or issuer names in X.509 objects are now displayed as UTF-8 strings
by default.
* TCP Fast Open (RFC7413) support is available on Linux, macOS, and FreeBSD

View File

@ -164,7 +164,10 @@
OPT_S_RECORD_PADDING, OPT_S_DEBUGBROKE, OPT_S_COMP, \
OPT_S_MINPROTO, OPT_S_MAXPROTO, \
OPT_S_NO_RENEGOTIATION, OPT_S_NO_MIDDLEBOX, OPT_S_NO_ETM, \
OPT_S_NO_EMS, OPT_S__LAST
OPT_S_NO_EMS, \
OPT_S_NO_TX_CERT_COMP, \
OPT_S_NO_RX_CERT_COMP, \
OPT_S__LAST
# define OPT_S_OPTIONS \
OPT_SECTION("TLS/SSL"), \
@ -176,6 +179,8 @@
{"bugs", OPT_S_BUGS, '-', "Turn on SSL bug compatibility"}, \
{"no_comp", OPT_S_NO_COMP, '-', "Disable SSL/TLS compression (default)" }, \
{"comp", OPT_S_COMP, '-', "Use SSL/TLS-level compression" }, \
{"no_tx_cert_comp", OPT_S_NO_TX_CERT_COMP, '-', "Disable sending TLSv1.3 compressed certificates" }, \
{"no_rx_cert_comp", OPT_S_NO_RX_CERT_COMP, '-', "Disable receiving TLSv1.3 compressed certificates" }, \
{"no_ticket", OPT_S_NOTICKET, '-', \
"Disable use of TLS session tickets"}, \
{"serverpref", OPT_S_SERVERPREF, '-', "Use server's cipher preferences"}, \
@ -233,6 +238,8 @@
case OPT_S_BUGS: \
case OPT_S_NO_COMP: \
case OPT_S_COMP: \
case OPT_S_NO_TX_CERT_COMP: \
case OPT_S_NO_RX_CERT_COMP: \
case OPT_S_NOTICKET: \
case OPT_S_SERVERPREF: \
case OPT_S_LEGACYRENEG: \

View File

@ -559,6 +559,7 @@ static STRINT_PAIR handshakes[] = {
{", CertificateStatus", SSL3_MT_CERTIFICATE_STATUS},
{", SupplementalData", SSL3_MT_SUPPLEMENTAL_DATA},
{", KeyUpdate", SSL3_MT_KEY_UPDATE},
{", CompressedCertificate", SSL3_MT_COMPRESSED_CERTIFICATE},
#ifndef OPENSSL_NO_NEXTPROTONEG
{", NextProto", SSL3_MT_NEXT_PROTO},
#endif
@ -685,6 +686,7 @@ static STRINT_PAIR tlsext_types[] = {
#ifdef TLSEXT_TYPE_extended_master_secret
{"extended master secret", TLSEXT_TYPE_extended_master_secret},
#endif
{"compress certificate", TLSEXT_TYPE_compress_certificate},
{"key share", TLSEXT_TYPE_key_share},
{"supported versions", TLSEXT_TYPE_supported_versions},
{"psk", TLSEXT_TYPE_psk},

View File

@ -716,7 +716,7 @@ typedef enum OPTION_choice {
OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_RECV_MAX_EARLY, OPT_EARLY_DATA,
OPT_S_NUM_TICKETS, OPT_ANTI_REPLAY, OPT_NO_ANTI_REPLAY, OPT_SCTP_LABEL_BUG,
OPT_HTTP_SERVER_BINMODE, OPT_NOCANAMES, OPT_IGNORE_UNEXPECTED_EOF, OPT_KTLS,
OPT_TFO,
OPT_TFO, OPT_CERT_COMP,
OPT_R_ENUM,
OPT_S_ENUM,
OPT_V_ENUM,
@ -843,6 +843,9 @@ const OPTIONS s_server_options[] = {
"No verify output except verify errors"},
{"ign_eof", OPT_IGN_EOF, '-', "Ignore input EOF (default when -quiet)"},
{"no_ign_eof", OPT_NO_IGN_EOF, '-', "Do not ignore input EOF"},
#ifndef OPENSSL_NO_COMP_ALG
{"cert_comp", OPT_CERT_COMP, '-', "Pre-compress server certificates"},
#endif
#ifndef OPENSSL_NO_OCSP
OPT_SECTION("OCSP"),
@ -1061,6 +1064,7 @@ int s_server_main(int argc, char *argv[])
int enable_ktls = 0;
#endif
int tfo = 0;
int cert_comp = 0;
/* Init of few remaining global variables */
local_argc = argc;
@ -1658,6 +1662,9 @@ int s_server_main(int argc, char *argv[])
case OPT_TFO:
tfo = 1;
break;
case OPT_CERT_COMP:
cert_comp = 1;
break;
}
}
@ -2243,6 +2250,14 @@ int s_server_main(int argc, char *argv[])
if (recv_max_early_data >= 0)
SSL_CTX_set_recv_max_early_data(ctx, recv_max_early_data);
if (cert_comp) {
BIO_printf(bio_s_out, "Compressing certificates\n");
if (!SSL_CTX_compress_certs(ctx, 0))
BIO_printf(bio_s_out, "Error compressing certs on ctx\n");
if (ctx2 != NULL && !SSL_CTX_compress_certs(ctx2, 0))
BIO_printf(bio_s_out, "Error compressing certs on ctx2\n");
}
if (rev)
server_cb = rev_body;
else if (www)

View File

@ -419,10 +419,10 @@ static const BIO_METHOD bio_meth_brotli = {
const BIO_METHOD *BIO_f_brotli(void)
{
#ifndef OPENSSL_NO_BROTLI
return &bio_meth_brotli;
#else
return NULL;
if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
return &bio_meth_brotli;
#endif
return NULL;
}
#ifndef OPENSSL_NO_BROTLI

View File

@ -481,10 +481,10 @@ static const BIO_METHOD bio_meth_zstd = {
const BIO_METHOD *BIO_f_zstd(void)
{
#ifndef OPENSSL_NO_ZSTD
return &bio_meth_zstd;
#else
return NULL;
if (RUN_ONCE(&zstd_once, ossl_comp_zstd_init))
return &bio_meth_zstd;
#endif
return NULL;
}
#ifndef OPENSSL_NO_ZSTD

View File

@ -19,12 +19,8 @@
static const ERR_STRING_DATA COMP_str_reasons[] = {
{ERR_PACK(ERR_LIB_COMP, 0, COMP_R_BROTLI_DECODE_ERROR),
"brotli decode error"},
{ERR_PACK(ERR_LIB_COMP, 0, COMP_R_BROTLI_DEFLATE_ERROR),
"brotli deflate error"},
{ERR_PACK(ERR_LIB_COMP, 0, COMP_R_BROTLI_ENCODE_ERROR),
"brotli encode error"},
{ERR_PACK(ERR_LIB_COMP, 0, COMP_R_BROTLI_INFLATE_ERROR),
"brotli inflate error"},
{ERR_PACK(ERR_LIB_COMP, 0, COMP_R_BROTLI_NOT_SUPPORTED),
"brotli not supported"},
{ERR_PACK(ERR_LIB_COMP, 0, COMP_R_ZLIB_DEFLATE_ERROR),

View File

@ -1271,6 +1271,7 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE:158:\
at least (D)TLS 1.2 needed in Suite B mode
SSL_R_BAD_CHANGE_CIPHER_SPEC:103:bad change cipher spec
SSL_R_BAD_CIPHER:186:bad cipher
SSL_R_BAD_COMPRESSION_ALGORITHM:326:bad compression algorithm
SSL_R_BAD_DATA:390:bad data
SSL_R_BAD_DATA_RETURNED_BY_CALLBACK:106:bad data returned by callback
SSL_R_BAD_DECOMPRESSION:107:bad decompression

View File

@ -2167,6 +2167,10 @@ DEPEND[html/man3/SSL_CTX_set0_CA_list.html]=man3/SSL_CTX_set0_CA_list.pod
GENERATE[html/man3/SSL_CTX_set0_CA_list.html]=man3/SSL_CTX_set0_CA_list.pod
DEPEND[man/man3/SSL_CTX_set0_CA_list.3]=man3/SSL_CTX_set0_CA_list.pod
GENERATE[man/man3/SSL_CTX_set0_CA_list.3]=man3/SSL_CTX_set0_CA_list.pod
DEPEND[html/man3/SSL_CTX_set1_cert_comp_preference.html]=man3/SSL_CTX_set1_cert_comp_preference.pod
GENERATE[html/man3/SSL_CTX_set1_cert_comp_preference.html]=man3/SSL_CTX_set1_cert_comp_preference.pod
DEPEND[man/man3/SSL_CTX_set1_cert_comp_preference.3]=man3/SSL_CTX_set1_cert_comp_preference.pod
GENERATE[man/man3/SSL_CTX_set1_cert_comp_preference.3]=man3/SSL_CTX_set1_cert_comp_preference.pod
DEPEND[html/man3/SSL_CTX_set1_curves.html]=man3/SSL_CTX_set1_curves.pod
GENERATE[html/man3/SSL_CTX_set1_curves.html]=man3/SSL_CTX_set1_curves.pod
DEPEND[man/man3/SSL_CTX_set1_curves.3]=man3/SSL_CTX_set1_curves.pod
@ -3313,6 +3317,7 @@ html/man3/SSL_CTX_sess_set_cache_size.html \
html/man3/SSL_CTX_sess_set_get_cb.html \
html/man3/SSL_CTX_sessions.html \
html/man3/SSL_CTX_set0_CA_list.html \
html/man3/SSL_CTX_set1_cert_comp_preference.html \
html/man3/SSL_CTX_set1_curves.html \
html/man3/SSL_CTX_set1_sigalgs.html \
html/man3/SSL_CTX_set1_verify_cert_store.html \
@ -3918,6 +3923,7 @@ man/man3/SSL_CTX_sess_set_cache_size.3 \
man/man3/SSL_CTX_sess_set_get_cb.3 \
man/man3/SSL_CTX_sessions.3 \
man/man3/SSL_CTX_set0_CA_list.3 \
man/man3/SSL_CTX_set1_cert_comp_preference.3 \
man/man3/SSL_CTX_set1_curves.3 \
man/man3/SSL_CTX_set1_sigalgs.3 \
man/man3/SSL_CTX_set1_verify_cert_store.3 \

View File

@ -83,6 +83,8 @@ B<openssl> B<s_client>
[B<-read_buf>]
[B<-ignore_unexpected_eof>]
[B<-bugs>]
[B<-no_tx_cert_comp>]
[B<-no_rx_cert_comp>]
[B<-comp>]
[B<-no_comp>]
[B<-brief>]
@ -601,6 +603,14 @@ For more information on shutting down a connection, see L<SSL_shutdown(3)>.
There are several known bugs in SSL and TLS implementations. Adding this
option enables various workarounds.
=item B<-no_tx_cert_comp>
Disables support for sending TLSv1.3 compressed certificates.
=item B<-no_rx_cert_comp>
Disables support for receiving TLSv1.3 compressed certificate.
=item B<-comp>
Enables support for SSL/TLS compression.
@ -930,7 +940,9 @@ The B<-certform> option has become obsolete in OpenSSL 3.0.0 and has no effect.
The B<-engine> option was deprecated in OpenSSL 3.0.
The -tfo option was added in OpenSSL 3.2.
The B<-tfo>, B<-no_tx_cert_comp>, and B<-no_rx_cert_comp> options were added
in OpenSSL 3.2.
=head1 COPYRIGHT

View File

@ -92,6 +92,8 @@ B<openssl> B<s_server>
[B<-naccept> I<+int>]
[B<-read_buf> I<+int>]
[B<-bugs>]
[B<-no_tx_cert_comp>]
[B<-no_rx_cert_comp>]
[B<-no_comp>]
[B<-comp>]
[B<-no_ticket>]
@ -139,6 +141,7 @@ B<openssl> B<s_server>
[B<-no_anti_replay>]
[B<-num_tickets>]
[B<-tfo>]
[B<-cert_comp>]
{- $OpenSSL::safe::opt_name_synopsis -}
{- $OpenSSL::safe::opt_version_synopsis -}
{- $OpenSSL::safe::opt_v_synopsis -}
@ -604,6 +607,14 @@ further information).
There are several known bugs in SSL and TLS implementations. Adding this
option enables various workarounds.
=item B<-no_tx_cert_comp>
Disables support for sending TLSv1.3 compressed certificates.
=item B<-no_rx_cert_comp>
Disables support for receiving TLSv1.3 compressed certificates.
=item B<-no_comp>
Disable negotiation of TLS compression.
@ -820,6 +831,9 @@ data that was sent will be rejected.
Enable acceptance of TCP Fast Open (RFC7413) connections.
=item B<-cert_comp>
Pre-compresses certificates (RFC8879) that will be sent during the handshake.
{- $OpenSSL::safe::opt_name_item -}
@ -947,7 +961,8 @@ The
The B<-srpvfile>, B<-srpuserseed>, and B<-engine>
option were deprecated in OpenSSL 3.0.
The -tfo option was added in OpenSSL 3.2.
The B<-tfo>, B<-no_tx_cert_comp>, and B<-no_rx_cert_comp> options were added
in OpenSSL 3.2.
=head1 COPYRIGHT

View File

@ -98,7 +98,7 @@ COMP_zstd_oneshot() returns a B<COMP_METHOD> for one-shot Zstandard compression.
BIO_f_zlib(), BIO_f_brotli() BIO_f_zstd() each return a B<BIO_METHOD> that may be used to
create a B<BIO> via B<BIO_new(3)> to read and write compressed files or streams.
The functions are only available if the corresponding algorithm is compiled into
the OpenSSL library.
the OpenSSL library. NULL may be returned if the algorithm fails to load dynamically.
=head1 NOTES
@ -123,11 +123,12 @@ L<SSL_set_options(3)> functions.
Compression is also used to support certificate compression as described
in RFC8879 L<https://datatracker.ietf.org/doc/html/rfc8879>.
It may be disabled via the SSL_OP_NO_CERTIFICATE_COMPRESSION option of
the L<SSL_CTX_set_options(3)> or L<SSL_set_options(3)> functions.
It may be disabled via the SSL_OP_NO_TX_CERTIFICATE_COMPRESSION and
SSL_OP_NO_RX_CERTIFICATE_COMPRESSION options of the
L<SSL_CTX_set_options(3)> or L<SSL_set_options(3)> functions.
COMP_zlib(), COMP_brotli() and COMP_zstd() are stream-based compression methods.
Internal state (including compression dictionary) is maintained between calls.
Internal state (including compression dictionary) is maintained between calls.
If an error is returned, the stream is corrupted, and should be closed.
COMP_brotli_oneshot() and COMP_zstd_oneshot() are not stream-based. These
@ -152,7 +153,8 @@ bytes stored in the output buffer I<out>. This may be 0. On failure,
COMP_get_name() returns a B<const char *> that must not be freed
on success, or NULL on failure.
BIO_f_zlib(), BIO_f_brotli() and BIO_f_zstd() return a B<BIO_METHOD>.
BIO_f_zlib(), BIO_f_brotli() and BIO_f_zstd() return NULL on error, and
a B<BIO_METHOD> on success.
=head1 SEE ALSO

View File

@ -162,6 +162,24 @@ This is a synonym for the B<-groups> command.
This sets the temporary curve used for ephemeral ECDH modes. Only used
by servers.
=item B<-tx_cert_comp>
Enables support for sending TLSv1.3 compressed certificates.
=item B<-no_tx_cert_comp>
Disables support for sending TLSv1.3 compressed certificates.
=item B<-rx_cert_comp>
Enables support for receiving TLSv1.3 compressed certificates.
=item B<-no_rx_cert_comp>
Disables support for receiving TLSv1.3 compressed certificates.
=item B<-comp>
The B<groups> argument is a curve name or the special value B<auto> which
picks an appropriate curve based on client and server preferences. The
curve can be either the B<NIST> name (e.g. B<P-256>) or an OpenSSL OID name
@ -535,6 +553,14 @@ B<SSL_OP_ENABLE_KTLS>.
B<StrictCertCheck>: Enable strict certificate checking. Equivalent to
setting B<SSL_CERT_FLAG_TLS_STRICT> with SSL_CTX_set_cert_flags().
B<TxCertificateCompression>: support sending compressed certificates, enabled by
default. Inverse of B<SSL_OP_NO_TX_CERTIFICATE_COMPRESSION>: that is,
B<-TxCertificateCompression> is the same as setting B<SSL_OP_NO_TX_CERTIFICATE_COMPRESSION>.
B<RxCertificateCompression>: support receiving compressed certificates, enabled by
default. Inverse of B<SSL_OP_NO_RX_CERTIFICATE_COMPRESSION>: that is,
B<-RxCertificateCompression> is the same as setting B<SSL_OP_NO_RX_CERTIFICATE_COMPRESSION>.
=item B<VerifyMode>
The B<value> argument is a comma separated list of flags to set.
@ -736,6 +762,9 @@ B<AllowNoDHEKEX> and B<PrioritizeChaCha> were added in OpenSSL 1.1.1.
The B<UnsafeLegacyServerConnect> option is no longer set by default from
OpenSSL 3.0.
The B<TxCertificateCompression> and B<RxCertificateCompression> options were
added in OpenSSL 3.2.
=head1 COPYRIGHT
Copyright 2012-2022 The OpenSSL Project Authors. All Rights Reserved.

View File

@ -0,0 +1,160 @@
=pod
=head1 NAME
SSL_CTX_set1_cert_comp_preference,
SSL_set1_cert_comp_preference,
SSL_CTX_compress_certs,
SSL_compress_certs,
SSL_CTX_get1_compressed_cert,
SSL_get1_compressed_cert,
SSL_CTX_set1_compressed_cert,
SSL_set1_compressed_cert - Certificate compression functions
=head1 SYNOPSIS
#include <openssl/ssl.h>
int SSL_CTX_set1_cert_comp_preference(SSL_CTX *ctx, int *algs, size_t len);
int SSL_set1_cert_comp_preference(SSL *ssl, int *algs, size_t len);
int SSL_CTX_compress_certs(SSL_CTX *ctx, int alg);
int SSL_compress_certs(SSL *ssl, int alg);
size_t SSL_CTX_get1_compressed_cert(SSL_CTX *ctx, int alg, unsigned char **data,
size_t *orig_len);
size_t SSL_get1_compressed_cert(SSL *ssl, int alg, unsigned char **data,
size_t *orig_len);
int SSL_CTX_set1_compressed_cert(SSL_CTX *ctx, int alg,
unsigned char *comp_data,
size_t comp_length, size_t orig_length);
int SSL_set1_compressed_cert(SSL *ssl, int alg, unsigned char *comp_data,
size_t comp_length, size_t orig_length);
=head1 DESCRIPTION
These functions control the certificate compression feature. Certificate
compression is only available for TLSv1.3 as defined in RFC8879.
SSL_CTX_set1_cert_comp_preference() and SSL_set1_cert_comp_preference() are used
to specify the preferred compression algorithms. The B<algs> argument is an array
of algorithms, and B<length> is number of elements in the B<algs> array. Only
those algorithms enabled in the library will be accepted in B<algs>, unknown
algorithms in B<algs> are ignored. On an error, the preference order is left
unmodified.
The following compression algorithms (B<alg> arguments) may be used:
=over 4
=item * TLSEXT_comp_cert_brotli
=item * TLSEXT_comp_cert_zlib
=item * TLSEXT_comp_cert_zstd
=back
The above is also the default preference order. If a preference order is not
specified, then the default preference order is sent to the peer and the
received peer's preference order will be used when compressing a certificate.
Otherwise, the configured preference order is sent to the peer and is used
to filter the peer's preference order.
SSL_CTX_compress_certs() and SSL_compress_certs() are used to pre-compress all
the configured certificates on an SSL_CTX/SSL object with algorithm B<alg>. If
B<alg> is 0, then the certificates are compressed with the algorithms specified
in the preference list. Calling these functions on a client SSL_CTX/SSL object
will result in an error, as only server certificates may be pre-compressed.
SSL_CTX_get1_compressed_cert() and SSL_get1_compressed_cert() are used to get
the pre-compressed certificate most recently set that may be stored for later
use. Calling these functions on a client SSL_CTX/SSL object will result in an
error, as only server certificates may be pre-compressed. The B<data> and
B<orig_len> arguments are required.
The compressed certificate data may be passed to SSL_CTX_set1_compressed_cert()
or SSL_set1_compressed_cert() to provide a pre-compressed version of the
most recently set certificate. This pre-compressed certificate can only be used
by a server.
=head1 NOTES
Each side of the connection sends their compression algorithm preference list
to their peer indicating compressed certificate support. The received preference
list is filtered by the configured preference list (i.e. the intersection is
saved). As the default list includes all the enabled algorithms, not specifying
a preference will allow any enabled algorithm by the peer. The filtered peer's
preference order is used to determine what algorithm to use when sending a
compressed certificate.
Only server certificates may be pre-compressed. Calling any of these functions
(except SSL_CTX_set1_cert_comp_preference()/SSL_set1_cert_comp_preference())
on a client SSL_CTX/SSL object will return an error. Client certificates are
compressed on-demand as unique context data from the server is compressed along
with the certificate.
For SSL_CTX_set1_cert_comp_preference() and SSL_set1_cert_comp_preference()
the B<len> argument is the size of the B<algs> argument in bytes.
The compressed certificate returned by SSL_CTX_get1_compressed_cert() and
SSL_get1_compressed_cert() is the last certificate set on the SSL_CTX/SSL object.
The certificate is copied by the function and the caller must free B<*data> via
OPENSSL_free().
The compressed certificate data set by SSL_CTX_set1_compressed_cert() and
SSL_set1_compressed_cert() is copied into the SSL_CTX/SSL object.
SSL_CTX_compress_certs() and SSL_compress_certs() return an error under the
following conditions:
=over 4
=item * If no certificates have been configured.
=item * If the specified algorithm B<alg> is not enabled.
=item * If B<alg> is 0 and no compression algorithms are enabled.
=back
Sending compressed certificates may be disabled on a connection via the
SSL_OP_NO_TX_CERTIFICATE_COMPRESSION option. Receiving compressed certificates
may be disabled on a connection via the SSL_OP_NO_RX_CERTIFICATE_COMPRESSION
option.
=head1 RETURN VALUES
SSL_CTX_set1_cert_comp_preference(),
SSL_set1_cert_comp_preference(),
SSL_CTX_compress_certs(),
SSL_compress_certs(),
SSL_CTX_set1_compressed_cert(), and
SSL_set1_compressed_cert()
return 1 for success and 0 on error.
SSL_CTX_get1_compressed_cert() and
SSL_get1_compressed_cert()
return the length of the allocated memory on success and 0 on error.
=head1 SEE ALSO
L<SSL_CTX_set_options(3)>,
L<SSL_CTX_use_certificate(3)>
=head1 HISTORY
These functions were added in OpenSSL 3.2.
=head1 COPYRIGHT
Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

View File

@ -214,6 +214,22 @@ functionality is not required. Those applications can turn this feature off by
setting this option. This is a server-side opton only. It is ignored by
clients.
=item SSL_OP_NO_TX_CERTIFICATE_COMPRESSION
Normally clients and servers will transparently attempt to negotiate the
RFC8879 certificate compression option on TLSv1.3 connections.
If this option is set, the certificate compression extension is ignored
upon receipt and compressed certificates will not be sent to the peer.
=item SSL_OP_NO_RX_CERTIFICATE_COMPRESSION
Normally clients and servers will transparently attempt to negotiate the
RFC8879 certificate compression option on TLSv1.3 connections.
If this option is set, the certificate compression extension will not be sent
and compressed certificates will not be accepted from the peer.
=item SSL_OP_NO_COMPRESSION
Do not use compression even if it is supported. This option is set by default.

View File

@ -24,17 +24,15 @@
* COMP reason codes.
*/
# define COMP_R_BROTLI_DECODE_ERROR 102
# define COMP_R_BROTLI_DEFLATE_ERROR 103
# define COMP_R_BROTLI_ENCODE_ERROR 106
# define COMP_R_BROTLI_INFLATE_ERROR 104
# define COMP_R_BROTLI_NOT_SUPPORTED 105
# define COMP_R_BROTLI_ENCODE_ERROR 103
# define COMP_R_BROTLI_NOT_SUPPORTED 104
# define COMP_R_ZLIB_DEFLATE_ERROR 99
# define COMP_R_ZLIB_INFLATE_ERROR 100
# define COMP_R_ZLIB_NOT_SUPPORTED 101
# define COMP_R_ZSTD_COMPRESS_ERROR 107
# define COMP_R_ZSTD_DECODE_ERROR 108
# define COMP_R_ZSTD_DECOMPRESS_ERROR 109
# define COMP_R_ZSTD_NOT_SUPPORTED 110
# define COMP_R_ZSTD_COMPRESS_ERROR 105
# define COMP_R_ZSTD_DECODE_ERROR 106
# define COMP_R_ZSTD_DECOMPRESS_ERROR 107
# define COMP_R_ZSTD_NOT_SUPPORTED 108
# endif
#endif

View File

@ -62,6 +62,12 @@ extern "C" {
# define RC4_INT {- $config{rc4_int} -}
# if defined(OPENSSL_NO_COMP) || (defined(OPENSSL_NO_BROTLI) && defined(OPENSSL_NO_ZSTD) && defined(OPENSSL_NO_ZLIB))
# define OPENSSL_NO_COMP_ALG
# else
# undef OPENSSL_NO_COMP_ALG
# endif
# ifdef __cplusplus
}
# endif

View File

@ -410,6 +410,15 @@ typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
* interoperability with CryptoPro CSP 3.x
*/
# define SSL_OP_CRYPTOPRO_TLSEXT_BUG SSL_OP_BIT(31)
/*
* Disable RFC8879 certificate compression
* SSL_OP_NO_TX_CERTIFICATE_COMPRESSION: don't send compressed certificates,
* and ignore the extension when received.
* SSL_OP_NO_RX_CERTIFICATE_COMPRESSION: don't send the extension, and
* subsequently indicating that receiving is not supported
*/
# define SSL_OP_NO_TX_CERTIFICATE_COMPRESSION SSL_OP_BIT(32)
# define SSL_OP_NO_RX_CERTIFICATE_COMPRESSION SSL_OP_BIT(33)
/*
* Option "collections."
@ -998,6 +1007,7 @@ typedef enum {
DTLS_ST_CR_HELLO_VERIFY_REQUEST,
TLS_ST_CR_SRVR_HELLO,
TLS_ST_CR_CERT,
TLS_ST_CR_COMP_CERT,
TLS_ST_CR_CERT_STATUS,
TLS_ST_CR_KEY_EXCH,
TLS_ST_CR_CERT_REQ,
@ -1007,6 +1017,7 @@ typedef enum {
TLS_ST_CR_FINISHED,
TLS_ST_CW_CLNT_HELLO,
TLS_ST_CW_CERT,
TLS_ST_CW_COMP_CERT,
TLS_ST_CW_KEY_EXCH,
TLS_ST_CW_CERT_VRFY,
TLS_ST_CW_CHANGE,
@ -1017,10 +1028,12 @@ typedef enum {
DTLS_ST_SW_HELLO_VERIFY_REQUEST,
TLS_ST_SW_SRVR_HELLO,
TLS_ST_SW_CERT,
TLS_ST_SW_COMP_CERT,
TLS_ST_SW_KEY_EXCH,
TLS_ST_SW_CERT_REQ,
TLS_ST_SW_SRVR_DONE,
TLS_ST_SR_CERT,
TLS_ST_SR_COMP_CERT,
TLS_ST_SR_KEY_EXCH,
TLS_ST_SR_CERT_VRFY,
TLS_ST_SR_NEXT_PROTO,
@ -2530,6 +2543,22 @@ void SSL_set_allow_early_data_cb(SSL *s,
const char *OSSL_default_cipher_list(void);
const char *OSSL_default_ciphersuites(void);
/* RFC8879 Certificate compression APIs */
int SSL_CTX_compress_certs(SSL_CTX *ctx, int alg);
int SSL_compress_certs(SSL *ssl, int alg);
int SSL_CTX_set1_cert_comp_preference(SSL_CTX *ctx, int *algs, size_t len);
int SSL_set1_cert_comp_preference(SSL *ssl, int *algs, size_t len);
int SSL_CTX_set1_compressed_cert(SSL_CTX *ctx, int algorithm, unsigned char *comp_data,
size_t comp_length, size_t orig_length);
int SSL_set1_compressed_cert(SSL *ssl, int algorithm, unsigned char *comp_data,
size_t comp_length, size_t orig_length);
size_t SSL_CTX_get1_compressed_cert(SSL_CTX *ctx, int alg, unsigned char **data, size_t *orig_len);
size_t SSL_get1_compressed_cert(SSL *ssl, int alg, unsigned char **data, size_t *orig_len);
# ifdef __cplusplus
}
# endif

View File

@ -317,6 +317,7 @@ extern "C" {
# define SSL3_MT_CERTIFICATE_STATUS 22
# define SSL3_MT_SUPPLEMENTAL_DATA 23
# define SSL3_MT_KEY_UPDATE 24
# define SSL3_MT_COMPRESSED_CERTIFICATE 25
# ifndef OPENSSL_NO_NEXTPROTONEG
# define SSL3_MT_NEXT_PROTO 67
# endif

View File

@ -27,6 +27,7 @@
# define SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE 158
# define SSL_R_BAD_CHANGE_CIPHER_SPEC 103
# define SSL_R_BAD_CIPHER 186
# define SSL_R_BAD_COMPRESSION_ALGORITHM 326
# define SSL_R_BAD_DATA 390
# define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106
# define SSL_R_BAD_DECOMPRESSION 107

View File

@ -134,6 +134,9 @@ extern "C" {
/* ExtensionType value from RFC7627 */
# define TLSEXT_TYPE_extended_master_secret 23
/* ExtensionType value from RFC8879 */
# define TLSEXT_TYPE_compress_certificate 27
/* ExtensionType value from RFC4507 */
# define TLSEXT_TYPE_session_ticket 35
@ -195,6 +198,15 @@ extern "C" {
# define TLSEXT_hash_num 10
/* Possible compression values from RFC8879 */
/* Not defined in RFC8879, but used internally for no-compression */
# define TLSEXT_comp_cert_none 0
# define TLSEXT_comp_cert_zlib 1
# define TLSEXT_comp_cert_brotli 2
# define TLSEXT_comp_cert_zstd 3
/* one more than the number of defined values - used as size of 0-terminated array */
# define TLSEXT_comp_cert_limit 4
/* Flag set for unrecognised algorithms */
# define TLSEXT_nid_unknown 0x1000000

View File

@ -19,6 +19,7 @@ SOURCE[../libssl]=\
ssl_asn1.c ssl_txt.c ssl_init.c ssl_conf.c ssl_mcnf.c \
bio_ssl.c ssl_err.c ssl_err_legacy.c tls_srp.c t1_trce.c ssl_utst.c \
statem/statem.c \
ssl_cert_comp.c \
tls_depr.c
# For shared builds we need to include the libcrypto packet.c and quic_vlint.c

View File

@ -74,6 +74,9 @@ CERT *ssl_cert_dup(CERT *cert)
{
CERT *ret = OPENSSL_zalloc(sizeof(*ret));
int i;
#ifndef OPENSSL_NO_COMP_ALG
int j;
#endif
if (ret == NULL)
return NULL;
@ -98,6 +101,7 @@ CERT *ssl_cert_dup(CERT *cert)
for (i = 0; i < SSL_PKEY_NUM; i++) {
CERT_PKEY *cpk = cert->pkeys + i;
CERT_PKEY *rpk = ret->pkeys + i;
if (cpk->x509 != NULL) {
rpk->x509 = cpk->x509;
X509_up_ref(rpk->x509);
@ -115,16 +119,22 @@ CERT *ssl_cert_dup(CERT *cert)
goto err;
}
}
if (cert->pkeys[i].serverinfo != NULL) {
if (cpk->serverinfo != NULL) {
/* Just copy everything. */
ret->pkeys[i].serverinfo =
OPENSSL_malloc(cert->pkeys[i].serverinfo_length);
if (ret->pkeys[i].serverinfo == NULL)
rpk->serverinfo = OPENSSL_memdup(cpk->serverinfo, cpk->serverinfo_length);
if (rpk->serverinfo == NULL)
goto err;
ret->pkeys[i].serverinfo_length = cert->pkeys[i].serverinfo_length;
memcpy(ret->pkeys[i].serverinfo,
cert->pkeys[i].serverinfo, cert->pkeys[i].serverinfo_length);
rpk->serverinfo_length = cpk->serverinfo_length;
}
#ifndef OPENSSL_NO_COMP_ALG
for (j = TLSEXT_comp_cert_none; j < TLSEXT_comp_cert_limit; j++) {
if (cpk->comp_cert[j] != NULL) {
if (!OSSL_COMP_CERT_up_ref(cpk->comp_cert[j]))
goto err;
rpk->comp_cert[j] = cpk->comp_cert[j];
}
}
#endif
}
/* Configured sigalgs copied across */
@ -198,6 +208,10 @@ CERT *ssl_cert_dup(CERT *cert)
void ssl_cert_clear_certs(CERT *c)
{
int i;
#ifndef OPENSSL_NO_COMP_ALG
int j;
#endif
if (c == NULL)
return;
for (i = 0; i < SSL_PKEY_NUM; i++) {
@ -211,6 +225,13 @@ void ssl_cert_clear_certs(CERT *c)
OPENSSL_free(cpk->serverinfo);
cpk->serverinfo = NULL;
cpk->serverinfo_length = 0;
#ifndef OPENSSL_NO_COMP_ALG
for (j = 0; j < TLSEXT_comp_cert_limit; j++) {
OSSL_COMP_CERT_free(cpk->comp_cert[j]);
cpk->comp_cert[j] = NULL;
cpk->cert_comp_used = 0;
}
#endif
}
}

479
ssl/ssl_cert_comp.c Normal file
View File

@ -0,0 +1,479 @@
/*
* Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "ssl_local.h"
#include "internal/e_os.h"
#include "internal/refcount.h"
size_t ossl_calculate_comp_expansion(int alg, size_t length)
{
size_t ret;
/*
* Uncompressibility expansion:
* ZLIB: N + 11 + 5 * (N >> 14)
* Brotli: per RFC7932: N + 5 + 3 * (N >> 16)
* ZSTD: N + 4 + 14 + 3 * (N >> 17) + 4
*/
switch (alg) {
case TLSEXT_comp_cert_zlib:
ret = length + 11 + 5 * (length >> 14);
break;
case TLSEXT_comp_cert_brotli:
ret = length + 5 + 3 * (length >> 16);
break;
case TLSEXT_comp_cert_zstd:
ret = length + 22 + 3 * (length >> 17);
break;
default:
return 0;
}
/* Check for overflow */
if (ret < length)
return 0;
return ret;
}
int ossl_comp_has_alg(int a)
{
#ifndef OPENSSL_NO_COMP_ALG
/* 0 means "any" algorithm */
if ((a == 0 || a == TLSEXT_comp_cert_brotli) && BIO_f_brotli() != NULL)
return 1;
if ((a == 0 || a == TLSEXT_comp_cert_zstd) && BIO_f_zstd() != NULL)
return 1;
if ((a == 0 || a == TLSEXT_comp_cert_zlib) && BIO_f_zlib() != NULL)
return 1;
#endif
return 0;
}
/* New operation Helper routine */
#ifndef OPENSSL_NO_COMP_ALG
static OSSL_COMP_CERT *OSSL_COMP_CERT_new(unsigned char *data, size_t len, size_t orig_len, int alg)
{
OSSL_COMP_CERT *ret = NULL;
if (!ossl_comp_has_alg(alg)
|| data == NULL
|| (ret = OPENSSL_zalloc(sizeof(*ret))) == NULL
|| (ret->lock = CRYPTO_THREAD_lock_new()) == NULL)
goto err;
ret->references = 1;
ret->data = data;
ret->len = len;
ret->orig_len = orig_len;
ret->alg = alg;
return ret;
err:
ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
OPENSSL_free(data);
OPENSSL_free(ret);
return NULL;
}
__owur static OSSL_COMP_CERT *OSSL_COMP_CERT_from_compressed_data(unsigned char *data, size_t len,
size_t orig_len, int alg)
{
return OSSL_COMP_CERT_new(OPENSSL_memdup(data, len), len, orig_len, alg);
}
__owur static OSSL_COMP_CERT *OSSL_COMP_CERT_from_uncompressed_data(unsigned char *data, size_t len,
int alg)
{
OSSL_COMP_CERT *ret = NULL;
size_t max_length;
int comp_length;
COMP_METHOD *method;
unsigned char *comp_data = NULL;
COMP_CTX *comp_ctx = NULL;
switch (alg) {
case TLSEXT_comp_cert_brotli:
method = COMP_brotli_oneshot();
break;
case TLSEXT_comp_cert_zlib:
method = COMP_zlib();
break;
case TLSEXT_comp_cert_zstd:
method = COMP_zstd_oneshot();
break;
default:
goto err;
}
if ((max_length = ossl_calculate_comp_expansion(alg, len)) == 0
|| method == NULL
|| (comp_ctx = COMP_CTX_new(method)) == NULL
|| (comp_data = OPENSSL_zalloc(max_length)) == NULL)
goto err;
comp_length = COMP_compress_block(comp_ctx, comp_data, max_length, data, len);
if (comp_length <= 0)
goto err;
ret = OSSL_COMP_CERT_new(comp_data, comp_length, len, alg);
comp_data = NULL;
err:
OPENSSL_free(comp_data);
COMP_CTX_free(comp_ctx);
return ret;
}
void OSSL_COMP_CERT_free(OSSL_COMP_CERT *cc)
{
int i;
if (cc == NULL)
return;
CRYPTO_DOWN_REF(&cc->references, &i, cc->lock);
REF_PRINT_COUNT("OSSL_COMP_CERT", cc);
if (i > 0)
return;
REF_ASSERT_ISNT(i < 0);
OPENSSL_free(cc->data);
CRYPTO_THREAD_lock_free(cc->lock);
OPENSSL_free(cc);
}
int OSSL_COMP_CERT_up_ref(OSSL_COMP_CERT *cc)
{
int i;
if (CRYPTO_UP_REF(&cc->references, &i, cc->lock) <= 0)
return 0;
REF_PRINT_COUNT("OSSL_COMP_CERT", cc);
REF_ASSERT_ISNT(i < 2);
return ((i > 1) ? 1 : 0);
}
static int ssl_set_cert_comp_pref(int *prefs, int *algs, size_t len)
{
size_t j = 0;
size_t i;
int found = 0;
int already_set[TLSEXT_comp_cert_limit];
int tmp_prefs[TLSEXT_comp_cert_limit];
/* Note that |len| is the number of |algs| elements */
/* clear all algorithms */
if (len == 0 || algs == NULL) {
memset(prefs, 0, sizeof(tmp_prefs));
return 1;
}
/* This will 0-terminate the array */
memset(tmp_prefs, 0, sizeof(tmp_prefs));
memset(already_set, 0, sizeof(already_set));
/* Include only those algorithms we support, ignoring duplicates and unknowns */
for (i = 0; i < len; i++) {
if (algs[i] != 0 && ossl_comp_has_alg(algs[i])) {
/* Check for duplicate */
if (already_set[algs[i]])
return 0;
tmp_prefs[j++] = algs[i];
already_set[algs[i]] = 1;
found = 1;
}
}
if (found)
memcpy(prefs, tmp_prefs, sizeof(tmp_prefs));
return found;
}
static size_t ssl_get_cert_to_compress(SSL *ssl, CERT_PKEY *cpk, unsigned char **data)
{
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
WPACKET tmppkt;
BUF_MEM buf = { 0 };
size_t ret = 0;
const SSL_METHOD *method = NULL;
if (sc == NULL
|| cpk == NULL
|| !sc->server
|| !SSL_in_before(ssl))
return 0;
/* Use the |tmppkt| for the to-be-compressed data */
if (!WPACKET_init(&tmppkt, &buf))
goto out;
/* no context present, add 0-length context */
if (!WPACKET_put_bytes_u8(&tmppkt, 0))
goto out;
/*
* ssl3_output_cert_chain() may generate an SSLfata() error,
* for this case, we want to ignore it
*/
sc->statem.ignore_fatal = 1;
ERR_set_mark();
/* Must get the certificate as TLSv1.3, restore before returning */
method = SSL_get_ssl_method(ssl);
if (!SSL_set_ssl_method(ssl, tlsv1_3_server_method()))
goto out;
if (!ssl3_output_cert_chain(sc, &tmppkt, cpk))
goto out;
WPACKET_get_total_written(&tmppkt, &ret);
out:
/* Don't leave errors in the queue */
ERR_pop_to_mark();
sc->statem.ignore_fatal = 0;
if (method != NULL && !SSL_set_ssl_method(ssl, method))
ret = 0;
WPACKET_cleanup(&tmppkt);
if (ret != 0 && data != NULL)
*data = (unsigned char *)buf.data;
else
OPENSSL_free(buf.data);
return ret;
}
static int ssl_compress_one_cert(SSL *ssl, CERT_PKEY *cpk, int alg)
{
unsigned char *cert_data = NULL;
OSSL_COMP_CERT *comp_cert = NULL;
size_t length;
if (cpk == NULL
|| alg == TLSEXT_comp_cert_none
|| !ossl_comp_has_alg(alg))
return 0;
if ((length = ssl_get_cert_to_compress(ssl, cpk, &cert_data)) == 0)
return 0;
comp_cert = OSSL_COMP_CERT_from_uncompressed_data(cert_data, length, alg);
OPENSSL_free(cert_data);
if (comp_cert == NULL)
return 0;
OSSL_COMP_CERT_free(cpk->comp_cert[alg]);
cpk->comp_cert[alg] = comp_cert;
return 1;
}
/* alg_in can be 0, meaning any/all algorithms */
static int ssl_compress_certs(SSL *ssl, CERT_PKEY *cpks, int alg_in)
{
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
int i;
int j;
int alg;
int count = 0;
if (sc == NULL
|| cpks == NULL
|| !ossl_comp_has_alg(alg_in))
return 0;
/* Look through the preferences to see what we have */
for (i = 0; i < TLSEXT_comp_cert_limit; i++) {
/*
* alg = 0 means compress for everything, but only for algorithms enabled
* alg != 0 means compress for that algorithm if enabled
*/
alg = sc->cert_comp_prefs[i];
if ((alg_in == 0 && alg != TLSEXT_comp_cert_none)
|| (alg_in != 0 && alg == alg_in)) {
for (j = 0; j < SSL_PKEY_NUM; j++) {
/* No cert, move on */
if (cpks[j].x509 == NULL)
continue;
if (!ssl_compress_one_cert(ssl, &cpks[j], alg))
return 0;
/* if the cert expanded, set the value in the CERT_PKEY to NULL */
if (cpks[j].comp_cert[alg]->len >= cpks[j].comp_cert[alg]->orig_len) {
OSSL_COMP_CERT_free(cpks[j].comp_cert[alg]);
cpks[j].comp_cert[alg] = NULL;
} else {
count++;
}
}
}
}
return (count > 0);
}
static size_t ssl_get_compressed_cert(SSL *ssl, CERT_PKEY *cpk, int alg, unsigned char **data,
size_t *orig_len)
{
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
size_t cert_len = 0;
size_t comp_len = 0;
unsigned char *cert_data = NULL;
OSSL_COMP_CERT *comp_cert = NULL;
if (sc == NULL
|| cpk == NULL
|| data == NULL
|| orig_len == NULL
|| !sc->server
|| !SSL_in_before(ssl)
|| !ossl_comp_has_alg(alg))
return 0;
if ((cert_len = ssl_get_cert_to_compress(ssl, cpk, &cert_data)) == 0)
goto err;
comp_cert = OSSL_COMP_CERT_from_uncompressed_data(cert_data, cert_len, alg);
OPENSSL_free(cert_data);
if (comp_cert == NULL)
goto err;
comp_len = comp_cert->len;
*orig_len = comp_cert->orig_len;
*data = comp_cert->data;
comp_cert->data = NULL;
err:
OSSL_COMP_CERT_free(comp_cert);
return comp_len;
}
static int ossl_set1_compressed_cert(CERT *cert, int algorithm,
unsigned char *comp_data, size_t comp_length,
size_t orig_length)
{
OSSL_COMP_CERT *comp_cert;
/* No explicit cert set */
if (cert == NULL || cert->key == NULL)
return 0;
comp_cert = OSSL_COMP_CERT_from_compressed_data(comp_data, comp_length,
orig_length, algorithm);
if (comp_cert == NULL)
return 0;
OSSL_COMP_CERT_free(cert->key->comp_cert[algorithm]);
cert->key->comp_cert[algorithm] = comp_cert;
return 1;
}
#endif
/*-
* Public API
*/
int SSL_CTX_set1_cert_comp_preference(SSL_CTX *ctx, int *algs, size_t len)
{
#ifndef OPENSSL_NO_COMP_ALG
return ssl_set_cert_comp_pref(ctx->cert_comp_prefs, algs, len);
#else
return 0;
#endif
}
int SSL_set1_cert_comp_preference(SSL *ssl, int *algs, size_t len)
{
#ifndef OPENSSL_NO_COMP_ALG
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
if (sc == NULL)
return 0;
return ssl_set_cert_comp_pref(sc->cert_comp_prefs, algs, len);
#else
return 0;
#endif
}
int SSL_compress_certs(SSL *ssl, int alg)
{
#ifndef OPENSSL_NO_COMP_ALG
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
if (sc == NULL || sc->cert == NULL)
return 0;
return ssl_compress_certs(ssl, sc->cert->pkeys, alg);
#endif
return 0;
}
int SSL_CTX_compress_certs(SSL_CTX *ctx, int alg)
{
int ret = 0;
#ifndef OPENSSL_NO_COMP_ALG
SSL *new = SSL_new(ctx);
if (new == NULL)
return 0;
ret = ssl_compress_certs(new, ctx->cert->pkeys, alg);
SSL_free(new);
#endif
return ret;
}
size_t SSL_get1_compressed_cert(SSL *ssl, int alg, unsigned char **data, size_t *orig_len)
{
#ifndef OPENSSL_NO_COMP_ALG
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
CERT_PKEY *cpk = NULL;
if (sc->cert != NULL)
cpk = sc->cert->key;
else
cpk = ssl->ctx->cert->key;
return ssl_get_compressed_cert(ssl, cpk, alg, data, orig_len);
#else
return 0;
#endif
}
size_t SSL_CTX_get1_compressed_cert(SSL_CTX *ctx, int alg, unsigned char **data, size_t *orig_len)
{
#ifndef OPENSSL_NO_COMP_ALG
size_t ret;
SSL *new = SSL_new(ctx);
ret = ssl_get_compressed_cert(new, ctx->cert->key, alg, data, orig_len);
SSL_free(new);
return ret;
#else
return 0;
#endif
}
int SSL_CTX_set1_compressed_cert(SSL_CTX *ctx, int algorithm, unsigned char *comp_data,
size_t comp_length, size_t orig_length)
{
#ifndef OPENSSL_NO_COMP_ALG
return ossl_set1_compressed_cert(ctx->cert, algorithm, comp_data, comp_length, orig_length);
#else
return 0;
#endif
}
int SSL_set1_compressed_cert(SSL *ssl, int algorithm, unsigned char *comp_data,
size_t comp_length, size_t orig_length)
{
#ifndef OPENSSL_NO_COMP_ALG
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
/* Cannot set a pre-compressed certificate on a client */
if (sc == NULL || !sc->server)
return 0;
return ossl_set1_compressed_cert(sc->cert, algorithm, comp_data, comp_length, orig_length);
#else
return 0;
#endif
}

View File

@ -397,7 +397,9 @@ static int cmd_Options(SSL_CONF_CTX *cctx, const char *value)
SSL_FLAG_TBL_INV("ExtendedMasterSecret", SSL_OP_NO_EXTENDED_MASTER_SECRET),
SSL_FLAG_TBL_INV("CANames", SSL_OP_DISABLE_TLSEXT_CA_NAMES),
SSL_FLAG_TBL("KTLS", SSL_OP_ENABLE_KTLS),
SSL_FLAG_TBL_CERT("StrictCertCheck", SSL_CERT_FLAG_TLS_STRICT)
SSL_FLAG_TBL_CERT("StrictCertCheck", SSL_CERT_FLAG_TLS_STRICT),
SSL_FLAG_TBL_INV("TxCertificateCompression", SSL_OP_NO_TX_CERTIFICATE_COMPRESSION),
SSL_FLAG_TBL_INV("RxCertificateCompression", SSL_OP_NO_RX_CERTIFICATE_COMPRESSION),
};
if (value == NULL)
return -3;
@ -707,6 +709,10 @@ static const ssl_conf_cmd_tbl ssl_conf_cmds[] = {
SSL_CONF_CMD_SWITCH("bugs", 0),
SSL_CONF_CMD_SWITCH("no_comp", 0),
SSL_CONF_CMD_SWITCH("comp", 0),
SSL_CONF_CMD_SWITCH("no_tx_cert_comp", 0),
SSL_CONF_CMD_SWITCH("tx_cert_comp", 0),
SSL_CONF_CMD_SWITCH("no_rx_cert_comp", 0),
SSL_CONF_CMD_SWITCH("rx_cert_comp", 0),
SSL_CONF_CMD_SWITCH("ecdh_single", SSL_CONF_FLAG_SERVER),
SSL_CONF_CMD_SWITCH("no_ticket", 0),
SSL_CONF_CMD_SWITCH("serverpref", SSL_CONF_FLAG_SERVER),
@ -787,6 +793,10 @@ static const ssl_switch_tbl ssl_cmd_switches[] = {
{SSL_OP_ALL, 0}, /* bugs */
{SSL_OP_NO_COMPRESSION, 0}, /* no_comp */
{SSL_OP_NO_COMPRESSION, SSL_TFLAG_INV}, /* comp */
{SSL_OP_NO_TX_CERTIFICATE_COMPRESSION, 0}, /* no_tx_cert_comp */
{SSL_OP_NO_TX_CERTIFICATE_COMPRESSION, SSL_TFLAG_INV}, /* tx_cert_comp */
{SSL_OP_NO_RX_CERTIFICATE_COMPRESSION, 0}, /* no_rx_cert_comp */
{SSL_OP_NO_RX_CERTIFICATE_COMPRESSION, SSL_TFLAG_INV}, /* rx_cert_comp */
{SSL_OP_SINGLE_ECDH_USE, 0}, /* ecdh_single */
{SSL_OP_NO_TICKET, 0}, /* no_ticket */
{SSL_OP_CIPHER_SERVER_PREFERENCE, 0}, /* serverpref */

View File

@ -26,6 +26,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CHANGE_CIPHER_SPEC),
"bad change cipher spec"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CIPHER), "bad cipher"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_COMPRESSION_ALGORITHM),
"bad compression algorithm"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "bad data"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK),
"bad data returned by callback"},

View File

@ -615,6 +615,9 @@ int ossl_ssl_connection_reset(SSL *s)
sc->first_packet = 0;
sc->key_update = SSL_KEY_UPDATE_NONE;
memset(sc->ext.compress_certificate_from_peer, 0,
sizeof(sc->ext.compress_certificate_from_peer));
sc->ext.compress_certificate_sent = 0;
EVP_MD_CTX_free(sc->pha_dgst);
sc->pha_dgst = NULL;
@ -890,6 +893,10 @@ SSL *ossl_ssl_connection_new(SSL_CTX *ctx)
s->job = NULL;
#ifndef OPENSSL_NO_COMP_ALG
memcpy(s->cert_comp_prefs, ctx->cert_comp_prefs, sizeof(s->cert_comp_prefs));
#endif
#ifndef OPENSSL_NO_CT
if (!SSL_set_ct_validation_callback(ssl, ctx->ct_validation_callback,
ctx->ct_validation_callback_arg))
@ -3658,6 +3665,9 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
const SSL_METHOD *meth)
{
SSL_CTX *ret = NULL;
#ifndef OPENSSL_NO_COMP_ALG
int i;
#endif
if (meth == NULL) {
ERR_raise(ERR_LIB_SSL, SSL_R_NULL_SSL_METHOD_PASSED);
@ -3831,6 +3841,21 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
ERR_clear_error();
}
# endif
#endif
#ifndef OPENSSL_NO_COMP_ALG
/*
* Set the default order: brotli, zlib, zstd
* Including only those enabled algorithms
*/
memset(ret->cert_comp_prefs, 0, sizeof(ret->cert_comp_prefs));
i = 0;
if (ossl_comp_has_alg(TLSEXT_comp_cert_brotli))
ret->cert_comp_prefs[i++] = TLSEXT_comp_cert_brotli;
if (ossl_comp_has_alg(TLSEXT_comp_cert_zlib))
ret->cert_comp_prefs[i++] = TLSEXT_comp_cert_zlib;
if (ossl_comp_has_alg(TLSEXT_comp_cert_zstd))
ret->cert_comp_prefs[i++] = TLSEXT_comp_cert_zstd;
#endif
/*
* Disable compression by default to prevent CRIME. Applications can

View File

@ -19,8 +19,8 @@
# include "internal/common.h" /* for HAS_PREFIX */
# include <openssl/buffer.h>
# include <openssl/comp.h>
# include <openssl/bio.h>
# include <openssl/comp.h>
# include <openssl/dsa.h>
# include <openssl/err.h>
# include <openssl/ssl.h>
@ -771,6 +771,7 @@ typedef enum tlsext_index_en {
TLSEXT_IDX_key_share,
TLSEXT_IDX_cookie,
TLSEXT_IDX_cryptopro_bug,
TLSEXT_IDX_compress_certificate,
TLSEXT_IDX_early_data,
TLSEXT_IDX_certificate_authorities,
TLSEXT_IDX_padding,
@ -1212,6 +1213,11 @@ struct ssl_ctx_st {
uint32_t disabled_mac_mask;
uint32_t disabled_mkey_mask;
uint32_t disabled_auth_mask;
#ifndef OPENSSL_NO_COMP_ALG
/* certificate compression preferences */
int cert_comp_prefs[TLSEXT_comp_cert_limit];
#endif
};
typedef struct cert_pkey_st CERT_PKEY;
@ -1699,6 +1705,11 @@ struct ssl_connection_st {
* selected.
*/
int tick_identity;
/* This is the list of algorithms the peer supports that we also support */
int compress_certificate_from_peer[TLSEXT_comp_cert_limit];
/* indicate that we sent the extension, so we'll accept it */
int compress_certificate_sent;
} ext;
/*
@ -1814,6 +1825,11 @@ struct ssl_connection_st {
*/
const struct sigalg_lookup_st **shared_sigalgs;
size_t shared_sigalgslen;
#ifndef OPENSSL_NO_COMP_ALG
/* certificate compression preferences */
int cert_comp_prefs[TLSEXT_comp_cert_limit];
#endif
};
# define SSL_CONNECTION_FROM_SSL_ONLY_int(ssl, c) \
@ -1986,6 +2002,21 @@ typedef struct dtls1_state_st {
# define EXPLICIT_CHAR2_CURVE_TYPE 2
# define NAMED_CURVE_TYPE 3
# ifndef OPENSSL_NO_COMP_ALG
struct ossl_comp_cert_st {
unsigned char *data;
size_t len;
size_t orig_len;
CRYPTO_REF_COUNT references;
CRYPTO_RWLOCK *lock;
int alg;
};
typedef struct ossl_comp_cert_st OSSL_COMP_CERT;
void OSSL_COMP_CERT_free(OSSL_COMP_CERT *c);
int OSSL_COMP_CERT_up_ref(OSSL_COMP_CERT *c);
# endif
struct cert_pkey_st {
X509 *x509;
EVP_PKEY *privatekey;
@ -2000,6 +2031,11 @@ struct cert_pkey_st {
*/
unsigned char *serverinfo;
size_t serverinfo_length;
# ifndef OPENSSL_NO_COMP_ALG
/* Compressed certificate data - index 0 is unused */
OSSL_COMP_CERT *comp_cert[TLSEXT_comp_cert_limit];
int cert_comp_used;
# endif
};
/* Retrieve Suite B flags */
# define tls1_suiteb(s) (s->cert->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS)
@ -2956,4 +2992,7 @@ static ossl_unused ossl_inline void ssl_tsan_counter(const SSL_CTX *ctx,
}
}
int ossl_comp_has_alg(int a);
size_t ossl_calculate_comp_expansion(int alg, size_t length);
#endif

View File

@ -37,6 +37,8 @@ const char *SSL_state_string_long(const SSL *s)
return "SSLv3/TLS read server hello";
case TLS_ST_CR_CERT:
return "SSLv3/TLS read server certificate";
case TLS_ST_CR_COMP_CERT:
return "TLSv1.3 read server compressed certificate";
case TLS_ST_CR_KEY_EXCH:
return "SSLv3/TLS read server key exchange";
case TLS_ST_CR_CERT_REQ:
@ -47,6 +49,8 @@ const char *SSL_state_string_long(const SSL *s)
return "SSLv3/TLS read server done";
case TLS_ST_CW_CERT:
return "SSLv3/TLS write client certificate";
case TLS_ST_CW_COMP_CERT:
return "TLSv1.3 write client compressed certificate";
case TLS_ST_CW_KEY_EXCH:
return "SSLv3/TLS write client key exchange";
case TLS_ST_CW_CERT_VRFY:
@ -71,6 +75,8 @@ const char *SSL_state_string_long(const SSL *s)
return "SSLv3/TLS write server hello";
case TLS_ST_SW_CERT:
return "SSLv3/TLS write certificate";
case TLS_ST_SW_COMP_CERT:
return "TLSv1.3 write server compressed certificate";
case TLS_ST_SW_KEY_EXCH:
return "SSLv3/TLS write key exchange";
case TLS_ST_SW_CERT_REQ:
@ -81,6 +87,8 @@ const char *SSL_state_string_long(const SSL *s)
return "SSLv3/TLS write server done";
case TLS_ST_SR_CERT:
return "SSLv3/TLS read client certificate";
case TLS_ST_SR_COMP_CERT:
return "TLSv1.3 read client compressed certificate";
case TLS_ST_SR_KEY_EXCH:
return "SSLv3/TLS read client key exchange";
case TLS_ST_SR_CERT_VRFY:
@ -150,6 +158,8 @@ const char *SSL_state_string(const SSL *s)
return "TRSH";
case TLS_ST_CR_CERT:
return "TRSC";
case TLS_ST_CR_COMP_CERT:
return "TRSCC";
case TLS_ST_CR_KEY_EXCH:
return "TRSKE";
case TLS_ST_CR_CERT_REQ:
@ -158,6 +168,8 @@ const char *SSL_state_string(const SSL *s)
return "TRSD";
case TLS_ST_CW_CERT:
return "TWCC";
case TLS_ST_CW_COMP_CERT:
return "TWCCC";
case TLS_ST_CW_KEY_EXCH:
return "TWCKE";
case TLS_ST_CW_CERT_VRFY:
@ -182,6 +194,8 @@ const char *SSL_state_string(const SSL *s)
return "TWSH";
case TLS_ST_SW_CERT:
return "TWSC";
case TLS_ST_SW_COMP_CERT:
return "TWSCC";
case TLS_ST_SW_KEY_EXCH:
return "TWSKE";
case TLS_ST_SW_CERT_REQ:
@ -190,6 +204,8 @@ const char *SSL_state_string(const SSL *s)
return "TWSD";
case TLS_ST_SR_CERT:
return "TRCC";
case TLS_ST_SR_COMP_CERT:
return "TRCCC";
case TLS_ST_SR_KEY_EXCH:
return "TRCKE";
case TLS_ST_SR_CERT_VRFY:

View File

@ -62,6 +62,13 @@ static int final_maxfragmentlen(SSL_CONNECTION *s, unsigned int context,
int sent);
static int init_post_handshake_auth(SSL_CONNECTION *s, unsigned int context);
static int final_psk(SSL_CONNECTION *s, unsigned int context, int sent);
static int tls_init_compress_certificate(SSL_CONNECTION *sc, unsigned int context);
static EXT_RETURN tls_construct_compress_certificate(SSL_CONNECTION *sc, WPACKET *pkt,
unsigned int context,
X509 *x, size_t chainidx);
static int tls_parse_compress_certificate(SSL_CONNECTION *sc, PACKET *pkt,
unsigned int context,
X509 *x, size_t chainidx);
/* Structure to define a built-in extension */
typedef struct extensions_definition_st {
@ -358,6 +365,15 @@ static const EXTENSION_DEFINITION ext_defs[] = {
| SSL_EXT_TLS1_2_AND_BELOW_ONLY,
NULL, NULL, NULL, tls_construct_stoc_cryptopro_bug, NULL, NULL
},
{
TLSEXT_TYPE_compress_certificate,
SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST
| SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
tls_init_compress_certificate,
tls_parse_compress_certificate, tls_parse_compress_certificate,
tls_construct_compress_certificate, tls_construct_compress_certificate,
NULL
},
{
TLSEXT_TYPE_early_data,
SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
@ -1746,3 +1762,112 @@ static int final_psk(SSL_CONNECTION *s, unsigned int context, int sent)
return 1;
}
static int tls_init_compress_certificate(SSL_CONNECTION *sc, unsigned int context)
{
memset(sc->ext.compress_certificate_from_peer, 0,
sizeof(sc->ext.compress_certificate_from_peer));
return 1;
}
/* The order these are put into the packet imply a preference order: [brotli, zlib, zstd] */
static EXT_RETURN tls_construct_compress_certificate(SSL_CONNECTION *sc, WPACKET *pkt,
unsigned int context,
X509 *x, size_t chainidx)
{
#ifndef OPENSSL_NO_COMP_ALG
int i;
if (!ossl_comp_has_alg(0))
return EXT_RETURN_NOT_SENT;
/* Do not indicate we support receiving compressed certificates */
if ((sc->options & SSL_OP_NO_RX_CERTIFICATE_COMPRESSION) != 0)
return EXT_RETURN_NOT_SENT;
if (sc->cert_comp_prefs[0] == TLSEXT_comp_cert_none)
return EXT_RETURN_NOT_SENT;
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_compress_certificate)
|| !WPACKET_start_sub_packet_u16(pkt)
|| !WPACKET_start_sub_packet_u8(pkt))
goto err;
for (i = 0; sc->cert_comp_prefs[i] != TLSEXT_comp_cert_none; i++) {
if (!WPACKET_put_bytes_u16(pkt, sc->cert_comp_prefs[i]))
goto err;
}
if (!WPACKET_close(pkt) || !WPACKET_close(pkt))
goto err;
sc->ext.compress_certificate_sent = 1;
return EXT_RETURN_SENT;
err:
SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
#else
return EXT_RETURN_NOT_SENT;
#endif
}
#ifndef OPENSSL_NO_COMP_ALG
static int tls_comp_in_pref(SSL_CONNECTION *sc, int alg)
{
int i;
/* ossl_comp_has_alg() considers 0 as "any" */
if (alg == 0)
return 0;
/* Make sure algorithm is enabled */
if (!ossl_comp_has_alg(alg))
return 0;
/* If no preferences are set, it's ok */
if (sc->cert_comp_prefs[0] == TLSEXT_comp_cert_none)
return 1;
/* Find the algorithm */
for (i = 0; i < TLSEXT_comp_cert_limit; i++)
if (sc->cert_comp_prefs[i] == alg)
return 1;
return 0;
}
#endif
int tls_parse_compress_certificate(SSL_CONNECTION *sc, PACKET *pkt, unsigned int context,
X509 *x, size_t chainidx)
{
#ifndef OPENSSL_NO_COMP_ALG
PACKET supported_comp_algs;
unsigned int comp;
int already_set[TLSEXT_comp_cert_limit];
int j = 0;
/* If no algorithms are available, ignore the extension */
if (!ossl_comp_has_alg(0))
return 1;
/* Ignore the extension and don't send compressed certificates */
if ((sc->options & SSL_OP_NO_TX_CERTIFICATE_COMPRESSION) != 0)
return 1;
if (!PACKET_as_length_prefixed_1(pkt, &supported_comp_algs)
|| PACKET_remaining(&supported_comp_algs) == 0) {
SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
return 0;
}
memset(already_set, 0, sizeof(already_set));
/*
* The preference array has real values, so take a look at each
* value coming in, and make sure it's in our preference list
* The array is 0 (i.e. "none") terminated
* The preference list only contains supported algorithms
*/
while (PACKET_get_1(&supported_comp_algs, &comp)) {
if (tls_comp_in_pref(sc, comp) && !already_set[comp]) {
sc->ext.compress_certificate_from_peer[j++] = comp;
already_set[comp] = 1;
}
}
#endif
return 1;
}

View File

@ -525,6 +525,7 @@ int SSL_extension_supported(unsigned int ext_type)
case TLSEXT_TYPE_certificate_authorities:
case TLSEXT_TYPE_psk:
case TLSEXT_TYPE_post_handshake_auth:
case TLSEXT_TYPE_compress_certificate:
return 1;
default:
return 0;

View File

@ -130,6 +130,7 @@ void ossl_statem_clear(SSL_CONNECTION *s)
s->statem.hand_state = TLS_ST_BEFORE;
ossl_statem_set_in_init(s, 1);
s->statem.no_cert_verify = 0;
s->statem.ignore_fatal = 0;
}
/*
@ -143,6 +144,15 @@ void ossl_statem_set_renegotiate(SSL_CONNECTION *s)
void ossl_statem_send_fatal(SSL_CONNECTION *s, int al)
{
/*
* Some public APIs may call internal functions that fatal error,
* which doesn't make sense outside the state machine. Those APIs
* that can handle a failure set this flag to avoid errors sending
* alerts. Example: getting a wire-formatted certificate for
* compression.
*/
if (s->statem.ignore_fatal)
return;
/* We shouldn't call SSLfatal() twice. Once is enough */
if (s->statem.in_init && s->statem.state == MSG_FLOW_ERROR)
return;

View File

@ -96,6 +96,7 @@ struct ossl_statem_st {
OSSL_HANDSHAKE_STATE request_state;
int in_init;
int read_state_first_init;
int ignore_fatal;
/* true when we are actually in SSL_accept() or SSL_connect() */
int in_handshake;
/*

View File

@ -135,6 +135,13 @@ static int ossl_statem_client13_read_transition(SSL_CONNECTION *s, int mt)
st->hand_state = TLS_ST_CR_CERT;
return 1;
}
#ifndef OPENSSL_NO_COMP_ALG
if (mt == SSL3_MT_COMPRESSED_CERTIFICATE
&& s->ext.compress_certificate_sent) {
st->hand_state = TLS_ST_CR_COMP_CERT;
return 1;
}
#endif
}
break;
@ -143,9 +150,17 @@ static int ossl_statem_client13_read_transition(SSL_CONNECTION *s, int mt)
st->hand_state = TLS_ST_CR_CERT;
return 1;
}
#ifndef OPENSSL_NO_COMP_ALG
if (mt == SSL3_MT_COMPRESSED_CERTIFICATE
&& s->ext.compress_certificate_sent) {
st->hand_state = TLS_ST_CR_COMP_CERT;
return 1;
}
#endif
break;
case TLS_ST_CR_CERT:
case TLS_ST_CR_COMP_CERT:
if (mt == SSL3_MT_CERTIFICATE_VERIFY) {
st->hand_state = TLS_ST_CR_CERT_VRFY;
return 1;
@ -309,6 +324,7 @@ int ossl_statem_client_read_transition(SSL_CONNECTION *s, int mt)
break;
case TLS_ST_CR_CERT:
case TLS_ST_CR_COMP_CERT:
/*
* The CertificateStatus message is optional even if
* |ext.status_expected| is set
@ -425,7 +441,10 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL_CONNECTION *s)
case TLS_ST_CR_CERT_REQ:
if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
st->hand_state = TLS_ST_CW_CERT;
if (s->ext.compress_certificate_from_peer[0] != TLSEXT_comp_cert_none)
st->hand_state = TLS_ST_CW_COMP_CERT;
else
st->hand_state = TLS_ST_CW_CERT;
return WRITE_TRAN_CONTINUE;
}
/*
@ -447,9 +466,12 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL_CONNECTION *s)
else if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0
&& s->hello_retry_request == SSL_HRR_NONE)
st->hand_state = TLS_ST_CW_CHANGE;
else if (s->s3.tmp.cert_req == 0)
st->hand_state = TLS_ST_CW_FINISHED;
else if (s->ext.compress_certificate_from_peer[0] != TLSEXT_comp_cert_none)
st->hand_state = TLS_ST_CW_COMP_CERT;
else
st->hand_state = (s->s3.tmp.cert_req != 0) ? TLS_ST_CW_CERT
: TLS_ST_CW_FINISHED;
st->hand_state = TLS_ST_CW_CERT;
return WRITE_TRAN_CONTINUE;
case TLS_ST_PENDING_EARLY_DATA_END:
@ -461,10 +483,15 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL_CONNECTION *s)
case TLS_ST_CW_END_OF_EARLY_DATA:
case TLS_ST_CW_CHANGE:
st->hand_state = (s->s3.tmp.cert_req != 0) ? TLS_ST_CW_CERT
: TLS_ST_CW_FINISHED;
if (s->s3.tmp.cert_req == 0)
st->hand_state = TLS_ST_CW_FINISHED;
else if (s->ext.compress_certificate_from_peer[0] != TLSEXT_comp_cert_none)
st->hand_state = TLS_ST_CW_COMP_CERT;
else
st->hand_state = TLS_ST_CW_CERT;
return WRITE_TRAN_CONTINUE;
case TLS_ST_CW_COMP_CERT:
case TLS_ST_CW_CERT:
/* If a non-empty Certificate we also send CertificateVerify */
st->hand_state = (s->s3.tmp.cert_req == 1) ? TLS_ST_CW_CERT_VRFY
@ -931,6 +958,13 @@ int ossl_statem_client_construct_message(SSL_CONNECTION *s,
*mt = SSL3_MT_CERTIFICATE;
break;
#ifndef OPENSSL_NO_COMP_ALG
case TLS_ST_CW_COMP_CERT:
*confunc = tls_construct_client_compressed_certificate;
*mt = SSL3_MT_COMPRESSED_CERTIFICATE;
break;
#endif
case TLS_ST_CW_KEY_EXCH:
*confunc = tls_construct_client_key_exchange;
*mt = SSL3_MT_CLIENT_KEY_EXCHANGE;
@ -980,6 +1014,7 @@ size_t ossl_statem_client_max_message_size(SSL_CONNECTION *s)
case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
return HELLO_VERIFY_REQUEST_MAX_LENGTH;
case TLS_ST_CR_COMP_CERT:
case TLS_ST_CR_CERT:
return s->max_cert_list;
@ -1046,6 +1081,11 @@ MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL_CONNECTION *s,
case TLS_ST_CR_CERT:
return tls_process_server_certificate(s, pkt);
#ifndef OPENSSL_NO_COMP_ALG
case TLS_ST_CR_COMP_CERT:
return tls_process_server_compressed_certificate(s, pkt);
#endif
case TLS_ST_CR_CERT_VRFY:
return tls_process_cert_verify(s, pkt);
@ -1097,6 +1137,7 @@ WORK_STATE ossl_statem_client_post_process_message(SSL_CONNECTION *s,
return WORK_ERROR;
case TLS_ST_CR_CERT:
case TLS_ST_CR_COMP_CERT:
return tls_post_process_server_certificate(s, wst);
case TLS_ST_CR_CERT_VRFY:
@ -1968,6 +2009,21 @@ WORK_STATE tls_post_process_server_certificate(SSL_CONNECTION *s,
return WORK_FINISHED_CONTINUE;
}
#ifndef OPENSSL_NO_COMP_ALG
MSG_PROCESS_RETURN tls_process_server_compressed_certificate(SSL_CONNECTION *sc, PACKET *pkt)
{
MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR;
PACKET tmppkt;
BUF_MEM *buf = BUF_MEM_new();
if (tls13_process_compressed_certificate(sc, pkt, &tmppkt, buf) != MSG_PROCESS_ERROR)
ret = tls_process_server_certificate(sc, &tmppkt);
BUF_MEM_free(buf);
return ret;
}
#endif
static int tls_process_ske_psk_preamble(SSL_CONNECTION *s, PACKET *pkt)
{
#ifndef OPENSSL_NO_PSK
@ -3531,6 +3587,7 @@ WORK_STATE tls_prepare_client_certificate(SSL_CONNECTION *s, WORK_STATE wst)
return WORK_FINISHED_CONTINUE;
} else {
s->s3.tmp.cert_req = 2;
s->ext.compress_certificate_from_peer[0] = TLSEXT_comp_cert_none;
if (!ssl3_digest_cached_records(s, 0)) {
/* SSLfatal() already called */
return WORK_ERROR;
@ -3538,6 +3595,10 @@ WORK_STATE tls_prepare_client_certificate(SSL_CONNECTION *s, WORK_STATE wst)
}
}
if (!SSL_CONNECTION_IS_TLS13(s)
|| (s->options & SSL_OP_NO_TX_CERTIFICATE_COMPRESSION) != 0)
s->ext.compress_certificate_from_peer[0] = TLSEXT_comp_cert_none;
if (s->post_handshake_auth == SSL_PHA_REQUESTED)
return WORK_FINISHED_STOP;
return WORK_FINISHED_CONTINUE;
@ -3587,6 +3648,97 @@ CON_FUNC_RETURN tls_construct_client_certificate(SSL_CONNECTION *s,
return CON_FUNC_SUCCESS;
}
#ifndef OPENSSL_NO_COMP_ALG
CON_FUNC_RETURN tls_construct_client_compressed_certificate(SSL_CONNECTION *sc,
WPACKET *pkt)
{
SSL *ssl = SSL_CONNECTION_GET_SSL(sc);
WPACKET tmppkt;
BUF_MEM *buf = NULL;
size_t length;
size_t max_length;
COMP_METHOD *method;
COMP_CTX *comp = NULL;
int comp_len;
int ret = 0;
int alg = sc->ext.compress_certificate_from_peer[0];
/* Note that sc->s3.tmp.cert_req == 2 is checked in write transition */
if ((buf = BUF_MEM_new()) == NULL || !WPACKET_init(&tmppkt, buf))
goto err;
/* Use the |tmppkt| for the to-be-compressed data */
if (sc->pha_context == NULL) {
/* no context available, add 0-length context */
if (!WPACKET_put_bytes_u8(&tmppkt, 0))
goto err;
} else if (!WPACKET_sub_memcpy_u8(&tmppkt, sc->pha_context, sc->pha_context_len))
goto err;
if (!ssl3_output_cert_chain(sc, &tmppkt, sc->cert->key)) {
/* SSLfatal() already called */
goto out;
}
/* continue with the real |pkt| */
if (!WPACKET_put_bytes_u16(pkt, alg)
|| !WPACKET_get_total_written(&tmppkt, &length)
|| !WPACKET_put_bytes_u24(pkt, length))
goto err;
switch (alg) {
case TLSEXT_comp_cert_zlib:
method = COMP_zlib();
break;
case TLSEXT_comp_cert_brotli:
method = COMP_brotli_oneshot();
break;
case TLSEXT_comp_cert_zstd:
method = COMP_zstd_oneshot();
break;
default:
goto err;
}
max_length = ossl_calculate_comp_expansion(alg, length);
if (!WPACKET_start_sub_packet_u24(pkt)
|| !WPACKET_reserve_bytes(pkt, max_length, NULL)
|| (comp = COMP_CTX_new(method)) == NULL)
goto err;
comp_len = COMP_compress_block(comp, WPACKET_get_curr(pkt), max_length,
(unsigned char *)buf->data, length);
if (comp_len <= 0)
goto err;
if (!WPACKET_allocate_bytes(pkt, comp_len, NULL)
|| !WPACKET_close(pkt))
goto err;
if (SSL_IS_FIRST_HANDSHAKE(sc)
&& (!ssl->method->ssl3_enc->change_cipher_state(sc,
SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_CLIENT_WRITE))) {
/*
* This is a fatal error, which leaves sc->enc_write_ctx in an
* inconsistent state and thus ssl3_send_alert may crash.
*/
SSLfatal(sc, SSL_AD_NO_ALERT, SSL_R_CANNOT_CHANGE_CIPHER);
goto out;
}
ret = 1;
goto out;
err:
SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
out:
WPACKET_cleanup(&tmppkt);
BUF_MEM_free(buf);
COMP_CTX_free(comp);
return ret;
}
#endif
int ssl3_check_cert_and_algorithm(SSL_CONNECTION *s)
{
const SSL_CERT_LOOKUP *clu;

View File

@ -2466,3 +2466,76 @@ int tls13_restore_handshake_digest_for_pha(SSL_CONNECTION *s)
}
return 1;
}
#ifndef OPENSSL_NO_COMP_ALG
MSG_PROCESS_RETURN tls13_process_compressed_certificate(SSL_CONNECTION *sc,
PACKET *pkt,
PACKET *tmppkt,
BUF_MEM *buf)
{
MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR;
int comp_alg;
COMP_METHOD *method = NULL;
COMP_CTX *comp = NULL;
size_t expected_length;
size_t comp_length;
int i;
int found = 0;
if (buf == NULL) {
SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
goto err;
}
if (!PACKET_get_net_2(pkt, (unsigned int*)&comp_alg)) {
SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, ERR_R_INTERNAL_ERROR);
goto err;
}
/* If we have a prefs list, make sure the algorithm is in it */
if (sc->cert_comp_prefs[0] != TLSEXT_comp_cert_none) {
for (i = 0; sc->cert_comp_prefs[i] != TLSEXT_comp_cert_none; i++) {
if (sc->cert_comp_prefs[i] == comp_alg) {
found = 1;
break;
}
}
if (!found) {
SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_COMPRESSION_ALGORITHM);
goto err;
}
}
if (!ossl_comp_has_alg(comp_alg)) {
SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_COMPRESSION_ALGORITHM);
goto err;
}
switch (comp_alg) {
case TLSEXT_comp_cert_zlib:
method = COMP_zlib();
break;
case TLSEXT_comp_cert_brotli:
method = COMP_brotli_oneshot();
break;
case TLSEXT_comp_cert_zstd:
method = COMP_zstd_oneshot();
break;
default:
SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_COMPRESSION_ALGORITHM);
goto err;
}
if (!PACKET_get_net_3_len(pkt, &expected_length)
|| !PACKET_get_net_3_len(pkt, &comp_length)
|| PACKET_remaining(pkt) != comp_length
|| !BUF_MEM_grow(buf, expected_length)
|| !PACKET_buf_init(tmppkt, (unsigned char *)buf->data, expected_length)
|| (comp = COMP_CTX_new(method)) == NULL
|| COMP_expand_block(comp, (unsigned char *)buf->data, expected_length,
(unsigned char*)PACKET_data(pkt), comp_length) != (int)expected_length) {
SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_DECOMPRESSION);
goto err;
}
ret = MSG_PROCESS_CONTINUE_PROCESSING;
err:
COMP_CTX_free(comp);
return ret;
}
#endif

View File

@ -129,6 +129,13 @@ __owur WORK_STATE tls_finish_handshake(SSL_CONNECTION *s, WORK_STATE wst,
int clearbufs, int stop);
__owur WORK_STATE dtls_wait_for_dry(SSL_CONNECTION *s);
#ifndef OPENSSL_NO_COMP_ALG
__owur MSG_PROCESS_RETURN tls13_process_compressed_certificate(SSL_CONNECTION *sc,
PACKET *pkt,
PACKET *tmppkt,
BUF_MEM *buf);
#endif
/* some client-only functions */
__owur CON_FUNC_RETURN tls_construct_client_hello(SSL_CONNECTION *s,
WPACKET *pkt);
@ -149,6 +156,10 @@ __owur WORK_STATE tls_prepare_client_certificate(SSL_CONNECTION *s,
WORK_STATE wst);
__owur CON_FUNC_RETURN tls_construct_client_certificate(SSL_CONNECTION *s,
WPACKET *pkt);
#ifndef OPENSSL_NO_COMP_ALG
__owur CON_FUNC_RETURN tls_construct_client_compressed_certificate(SSL_CONNECTION *sc,
WPACKET *pkt);
#endif
__owur int ssl_do_client_cert_cb(SSL_CONNECTION *s, X509 **px509,
EVP_PKEY **ppkey);
__owur CON_FUNC_RETURN tls_construct_client_key_exchange(SSL_CONNECTION *s,
@ -163,6 +174,10 @@ __owur MSG_PROCESS_RETURN tls_process_server_certificate(SSL_CONNECTION *s,
PACKET *pkt);
__owur WORK_STATE tls_post_process_server_certificate(SSL_CONNECTION *s,
WORK_STATE wst);
#ifndef OPENSSL_NO_COMP_ALG
__owur MSG_PROCESS_RETURN tls_process_server_compressed_certificate(SSL_CONNECTION *sc,
PACKET *pkt);
#endif
__owur int ssl3_check_cert_and_algorithm(SSL_CONNECTION *s);
#ifndef OPENSSL_NO_NEXTPROTONEG
__owur CON_FUNC_RETURN tls_construct_next_proto(SSL_CONNECTION *s, WPACKET *pkt);
@ -183,6 +198,10 @@ __owur CON_FUNC_RETURN dtls_construct_hello_verify_request(SSL_CONNECTION *s,
WPACKET *pkt);
__owur CON_FUNC_RETURN tls_construct_server_certificate(SSL_CONNECTION *s,
WPACKET *pkt);
#ifndef OPENSSL_NO_COMP_ALG
__owur CON_FUNC_RETURN tls_construct_server_compressed_certificate(SSL_CONNECTION *sc,
WPACKET *pkt);
#endif
__owur CON_FUNC_RETURN tls_construct_server_key_exchange(SSL_CONNECTION *s,
WPACKET *pkt);
__owur CON_FUNC_RETURN tls_construct_certificate_request(SSL_CONNECTION *s,
@ -191,6 +210,10 @@ __owur CON_FUNC_RETURN tls_construct_server_done(SSL_CONNECTION *s,
WPACKET *pkt);
__owur MSG_PROCESS_RETURN tls_process_client_certificate(SSL_CONNECTION *s,
PACKET *pkt);
#ifndef OPENSSL_NO_COMP_ALG
__owur MSG_PROCESS_RETURN tls_process_client_compressed_certificate(SSL_CONNECTION *sc,
PACKET *pkt);
#endif
__owur MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL_CONNECTION *s,
PACKET *pkt);
__owur WORK_STATE tls_post_process_client_key_exchange(SSL_CONNECTION *s,

View File

@ -26,6 +26,7 @@
#include <openssl/trace.h>
#include <openssl/core_names.h>
#include <openssl/asn1t.h>
#include <openssl/comp.h>
#define TICKET_NONCE_SIZE 8
@ -91,6 +92,13 @@ static int ossl_statem_server13_read_transition(SSL_CONNECTION *s, int mt)
st->hand_state = TLS_ST_SR_CERT;
return 1;
}
#ifndef OPENSSL_NO_COMP_ALG
if (mt == SSL3_MT_COMPRESSED_CERTIFICATE
&& s->ext.compress_certificate_sent) {
st->hand_state = TLS_ST_SR_COMP_CERT;
return 1;
}
#endif
} else {
if (mt == SSL3_MT_FINISHED) {
st->hand_state = TLS_ST_SR_FINISHED;
@ -99,6 +107,7 @@ static int ossl_statem_server13_read_transition(SSL_CONNECTION *s, int mt)
}
break;
case TLS_ST_SR_COMP_CERT:
case TLS_ST_SR_CERT:
if (s->session->peer == NULL) {
if (mt == SSL3_MT_FINISHED) {
@ -128,10 +137,18 @@ static int ossl_statem_server13_read_transition(SSL_CONNECTION *s, int mt)
if (s->early_data_state == SSL_EARLY_DATA_READING)
break;
if (mt == SSL3_MT_CERTIFICATE
&& s->post_handshake_auth == SSL_PHA_REQUESTED) {
st->hand_state = TLS_ST_SR_CERT;
return 1;
if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
if (mt == SSL3_MT_CERTIFICATE) {
st->hand_state = TLS_ST_SR_CERT;
return 1;
}
#ifndef OPENSSL_NO_COMP_ALG
if (mt == SSL3_MT_COMPRESSED_CERTIFICATE
&& s->ext.compress_certificate_sent) {
st->hand_state = TLS_ST_SR_COMP_CERT;
return 1;
}
#endif
}
if (mt == SSL3_MT_KEY_UPDATE) {
@ -356,6 +373,27 @@ static int send_server_key_exchange(SSL_CONNECTION *s)
return 0;
}
/*
* Used to determine if we shoud send a CompressedCertificate message
*
* Returns the algorithm to use, TLSEXT_comp_cert_none means no compression
*/
static int get_compressed_certificate_alg(SSL_CONNECTION *sc)
{
#ifndef OPENSSL_NO_COMP_ALG
int *alg = sc->ext.compress_certificate_from_peer;
if (sc->s3.tmp.cert == NULL)
return TLSEXT_comp_cert_none;
for (; *alg != TLSEXT_comp_cert_none; alg++) {
if (sc->s3.tmp.cert->comp_cert[*alg] != NULL)
return *alg;
}
#endif
return TLSEXT_comp_cert_none;
}
/*
* Should we send a CertificateRequest message?
*
@ -468,6 +506,8 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL_CONNECTION *s)
st->hand_state = TLS_ST_SW_FINISHED;
else if (send_certificate_request(s))
st->hand_state = TLS_ST_SW_CERT_REQ;
else if (get_compressed_certificate_alg(s) != TLSEXT_comp_cert_none)
st->hand_state = TLS_ST_SW_COMP_CERT;
else
st->hand_state = TLS_ST_SW_CERT;
@ -477,11 +517,14 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL_CONNECTION *s)
if (s->post_handshake_auth == SSL_PHA_REQUEST_PENDING) {
s->post_handshake_auth = SSL_PHA_REQUESTED;
st->hand_state = TLS_ST_OK;
} else if (get_compressed_certificate_alg(s) != TLSEXT_comp_cert_none) {
st->hand_state = TLS_ST_SW_COMP_CERT;
} else {
st->hand_state = TLS_ST_SW_CERT;
}
return WRITE_TRAN_CONTINUE;
case TLS_ST_SW_COMP_CERT:
case TLS_ST_SW_CERT:
st->hand_state = TLS_ST_SW_CERT_VRFY;
return WRITE_TRAN_CONTINUE;
@ -975,6 +1018,18 @@ WORK_STATE ossl_statem_server_post_work(SSL_CONNECTION *s, WORK_STATE wst)
if (s->post_handshake_auth == SSL_PHA_REQUEST_PENDING) {
if (statem_flush(s) != 1)
return WORK_MORE_A;
} else {
if (!SSL_CONNECTION_IS_TLS13(s)
|| (s->options & SSL_OP_NO_TX_CERTIFICATE_COMPRESSION) != 0)
s->ext.compress_certificate_from_peer[0] = TLSEXT_comp_cert_none;
}
break;
case TLS_ST_SW_ENCRYPTED_EXTENSIONS:
if (!s->hit && !send_certificate_request(s)) {
if (!SSL_CONNECTION_IS_TLS13(s)
|| (s->options & SSL_OP_NO_TX_CERTIFICATE_COMPRESSION) != 0)
s->ext.compress_certificate_from_peer[0] = TLSEXT_comp_cert_none;
}
break;
@ -1059,6 +1114,13 @@ int ossl_statem_server_construct_message(SSL_CONNECTION *s,
*mt = SSL3_MT_CERTIFICATE;
break;
#ifndef OPENSSL_NO_COMP_ALG
case TLS_ST_SW_COMP_CERT:
*confunc = tls_construct_server_compressed_certificate;
*mt = SSL3_MT_COMPRESSED_CERTIFICATE;
break;
#endif
case TLS_ST_SW_CERT_VRFY:
*confunc = tls_construct_cert_verify;
*mt = SSL3_MT_CERTIFICATE_VERIFY;
@ -1153,6 +1215,7 @@ size_t ossl_statem_server_max_message_size(SSL_CONNECTION *s)
case TLS_ST_SR_END_OF_EARLY_DATA:
return END_OF_EARLY_DATA_MAX_LENGTH;
case TLS_ST_SR_COMP_CERT:
case TLS_ST_SR_CERT:
return s->max_cert_list;
@ -1201,6 +1264,11 @@ MSG_PROCESS_RETURN ossl_statem_server_process_message(SSL_CONNECTION *s,
case TLS_ST_SR_CERT:
return tls_process_client_certificate(s, pkt);
#ifndef OPENSSL_NO_COMP_ALG
case TLS_ST_SR_COMP_CERT:
return tls_process_client_compressed_certificate(s, pkt);
#endif
case TLS_ST_SR_KEY_EXCH:
return tls_process_client_key_exchange(s, pkt);
@ -3633,6 +3701,21 @@ MSG_PROCESS_RETURN tls_process_client_certificate(SSL_CONNECTION *s,
return ret;
}
#ifndef OPENSSL_NO_COMP_ALG
MSG_PROCESS_RETURN tls_process_client_compressed_certificate(SSL_CONNECTION *sc, PACKET *pkt)
{
MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR;
PACKET tmppkt;
BUF_MEM *buf = BUF_MEM_new();
if (tls13_process_compressed_certificate(sc, pkt, &tmppkt, buf) != MSG_PROCESS_ERROR)
ret = tls_process_client_certificate(sc, &tmppkt);
BUF_MEM_free(buf);
return ret;
}
#endif
CON_FUNC_RETURN tls_construct_server_certificate(SSL_CONNECTION *s, WPACKET *pkt)
{
CERT_PKEY *cpk = s->s3.tmp.cert;
@ -3658,6 +3741,32 @@ CON_FUNC_RETURN tls_construct_server_certificate(SSL_CONNECTION *s, WPACKET *pkt
return CON_FUNC_SUCCESS;
}
#ifndef OPENSSL_NO_COMP_ALG
CON_FUNC_RETURN tls_construct_server_compressed_certificate(SSL_CONNECTION *sc, WPACKET *pkt)
{
int alg = get_compressed_certificate_alg(sc);
OSSL_COMP_CERT *cc = sc->s3.tmp.cert->comp_cert[alg];
if (!ossl_assert(cc != NULL)) {
SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return 0;
}
/*
* Server can't compress on-demand
* Use pre-compressed certificate
*/
if (!WPACKET_put_bytes_u16(pkt, alg)
|| !WPACKET_put_bytes_u24(pkt, cc->orig_len)
|| !WPACKET_start_sub_packet_u24(pkt)
|| !WPACKET_memcpy(pkt, cc->data, cc->len)
|| !WPACKET_close(pkt))
return 0;
sc->s3.tmp.cert->cert_comp_used++;
return 1;
}
#endif
static int create_ticket_prequel(SSL_CONNECTION *s, WPACKET *pkt,
uint32_t age_add, unsigned char *tick_nonce)
{

View File

@ -97,6 +97,7 @@ static const ssl_trace_tbl ssl_handshake_tbl[] = {
{SSL3_MT_CERTIFICATE_STATUS, "CertificateStatus"},
{SSL3_MT_SUPPLEMENTAL_DATA, "SupplementalData"},
{SSL3_MT_KEY_UPDATE, "KeyUpdate"},
{SSL3_MT_COMPRESSED_CERTIFICATE, "CompressedCertificate"},
# ifndef OPENSSL_NO_NEXTPROTONEG
{SSL3_MT_NEXT_PROTO, "NextProto"},
# endif
@ -478,6 +479,7 @@ static const ssl_trace_tbl ssl_exts_tbl[] = {
{TLSEXT_TYPE_padding, "padding"},
{TLSEXT_TYPE_encrypt_then_mac, "encrypt_then_mac"},
{TLSEXT_TYPE_extended_master_secret, "extended_master_secret"},
{TLSEXT_TYPE_compress_certificate, "compress_certificate"},
{TLSEXT_TYPE_session_ticket, "session_ticket"},
{TLSEXT_TYPE_psk, "psk"},
{TLSEXT_TYPE_early_data, "early_data"},
@ -617,6 +619,13 @@ static const ssl_trace_tbl ssl_key_update_tbl[] = {
{SSL_KEY_UPDATE_REQUESTED, "update_requested"}
};
static const ssl_trace_tbl ssl_comp_cert_tbl[] = {
{TLSEXT_comp_cert_none, "none"},
{TLSEXT_comp_cert_zlib, "zlib"},
{TLSEXT_comp_cert_brotli, "brotli"},
{TLSEXT_comp_cert_zstd, "zstd"}
};
static void ssl_print_hex(BIO *bio, int indent, const char *name,
const unsigned char *msg, size_t msglen)
{
@ -721,6 +730,14 @@ static int ssl_print_extension(BIO *bio, int indent, int server,
BIO_printf(bio, "extension_type=%s(%d), length=%d\n",
ssl_trace_str(extype, ssl_exts_tbl), extype, (int)extlen);
switch (extype) {
case TLSEXT_TYPE_compress_certificate:
if (extlen < 1)
return 0;
xlen = ext[0];
if (extlen != xlen + 1)
return 0;
return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 2, ssl_comp_cert_tbl);
case TLSEXT_TYPE_max_fragment_length:
if (extlen < 1)
return 0;
@ -1287,6 +1304,73 @@ static int ssl_print_certificates(BIO *bio, const SSL_CONNECTION *sc, int server
return 1;
}
static int ssl_print_compressed_certificates(BIO *bio, const SSL_CONNECTION *sc,
int server, int indent,
const unsigned char *msg,
size_t msglen)
{
size_t uclen;
size_t clen;
unsigned int alg;
int ret = 1;
#ifndef OPENSSL_NO_COMP_ALG
COMP_METHOD *method;
COMP_CTX *comp = NULL;
unsigned char* ucdata = NULL;
#endif
if (msglen < 8)
return 0;
alg = (msg[0] << 8) | msg[1];
uclen = (msg[2] << 16) | (msg[3] << 8) | msg[4];
clen = (msg[5] << 16) | (msg[6] << 8) | msg[7];
if (msglen != clen + 8)
return 0;
msg += 8;
BIO_indent(bio, indent, 80);
BIO_printf(bio, "Compression type=%s (0x%04x)\n", ssl_trace_str(alg, ssl_comp_cert_tbl), alg);
BIO_indent(bio, indent, 80);
BIO_printf(bio, "Uncompressed length=%d\n", (int)uclen);
BIO_indent(bio, indent, 80);
BIO_printf(bio, "Compressed length=%d, Ratio=%f:1\n", (int)clen, (float)uclen / (float)clen);
BIO_dump_indent(bio, (const char *)msg, clen, indent);
#ifndef OPENSSL_NO_COMP_ALG
if (!ossl_comp_has_alg(alg))
return 0;
if ((ucdata = OPENSSL_malloc(uclen)) == NULL)
return 0;
switch (alg) {
case TLSEXT_comp_cert_zlib:
method = COMP_zlib();
break;
case TLSEXT_comp_cert_brotli:
method = COMP_brotli_oneshot();
break;
case TLSEXT_comp_cert_zstd:
method = COMP_zstd_oneshot();
break;
default:
goto err;
}
if ((comp = COMP_CTX_new(method)) == NULL
|| COMP_expand_block(comp, ucdata, uclen, (unsigned char*)msg, clen) != (int)uclen)
goto err;
ret = ssl_print_certificates(bio, sc, server, indent, ucdata, uclen);
err:
COMP_CTX_free(comp);
OPENSSL_free(ucdata);
#endif
return ret;
}
static int ssl_print_cert_request(BIO *bio, int indent, const SSL_CONNECTION *sc,
const unsigned char *msg, size_t msglen)
{
@ -1486,6 +1570,11 @@ static int ssl_print_handshake(BIO *bio, const SSL_CONNECTION *sc, int server,
return 0;
break;
case SSL3_MT_COMPRESSED_CERTIFICATE:
if (!ssl_print_compressed_certificates(bio, sc, server, indent + 2, msg, msglen))
return 0;
break;
case SSL3_MT_CERTIFICATE_VERIFY:
if (!ssl_print_signature(bio, indent + 2, sc, &msg, &msglen))
return 0;

View File

@ -44,6 +44,8 @@ static int do_bio_comp_test(const BIO_METHOD *meth, size_t size)
int ret = 0;
/* Compress */
if (!TEST_ptr(meth))
goto err;
if (!TEST_ptr(bcomp = BIO_new(meth)))
goto err;
if (!TEST_ptr(bmem = BIO_new(BIO_s_mem())))

View File

@ -73,6 +73,10 @@ IF[{- !$disabled{tests} -}]
PROGRAMS{noinst}=priority_queue_test event_queue_test
ENDIF
IF[{- !$disabled{comp} && (!$disabled{brotli} || !$disabled{zstd} || !$disabled{zlib}) -}]
PROGRAMS{noinst}=cert_comp_test
ENDIF
SOURCE[confdump]=confdump.c
INCLUDE[confdump]=../include ../apps/include
DEPEND[confdump]=../libcrypto
@ -1022,6 +1026,10 @@ ENDIF
INCLUDE[quic_ackm_test]=../include ../apps/include
DEPEND[quic_ackm_test]=../libcrypto.a ../libssl.a libtestutil.a
SOURCE[cert_comp_test]=cert_comp_test.c helpers/ssltestlib.c
INCLUDE[cert_comp_test]=../include ../apps/include ..
DEPEND[cert_comp_test]=../libcrypto ../libssl libtestutil.a
{-
use File::Spec::Functions;
use File::Basename;

281
test/cert_comp_test.c Normal file
View File

@ -0,0 +1,281 @@
/*
* Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/*
* We need access to the deprecated low level HMAC APIs for legacy purposes
* when the deprecated calls are not hidden
*/
#ifndef OPENSSL_NO_DEPRECATED_3_0
# define OPENSSL_SUPPRESS_DEPRECATED
#endif
#include <openssl/ssl.h>
#include "internal/nelem.h"
#include "helpers/ssltestlib.h"
#include "testutil.h"
#include "../ssl/ssl_local.h"
#undef OSSL_NO_USABLE_TLS1_3
#if defined(OPENSSL_NO_TLS1_3) \
|| (defined(OPENSSL_NO_EC) && defined(OPENSSL_NO_DH))
/*
* If we don't have ec or dh then there are no built-in groups that are usable
* with TLSv1.3
*/
# define OSSL_NO_USABLE_TLS1_3
#endif
#if !defined(OSSL_NO_USEABLE_TLS1_3)
static char *certsdir = NULL;
static char *cert = NULL;
static char *privkey = NULL;
static int client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
{
X509 *xcert;
EVP_PKEY *privpkey;
BIO *in = NULL;
BIO *priv_in = NULL;
/* Check that SSL_get0_peer_certificate() returns something sensible */
if (!TEST_ptr(SSL_get0_peer_certificate(ssl)))
return 0;
in = BIO_new_file(cert, "r");
if (!TEST_ptr(in))
return 0;
if (!TEST_ptr(xcert = X509_new_ex(NULL, NULL))
|| !TEST_ptr(PEM_read_bio_X509(in, &xcert, NULL, NULL))
|| !TEST_ptr(priv_in = BIO_new_file(privkey, "r"))
|| !TEST_ptr(privpkey = PEM_read_bio_PrivateKey_ex(priv_in, NULL,
NULL, NULL,
NULL, NULL)))
goto err;
*x509 = xcert;
*pkey = privpkey;
BIO_free(in);
BIO_free(priv_in);
return 1;
err:
X509_free(xcert);
BIO_free(in);
BIO_free(priv_in);
return 0;
}
static int verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
return 1;
}
/*
* Test 0 = app pre-compresses certificate in SSL
* Test 1 = app pre-compresses certificate in SSL_CTX
* Test 2 = app pre-compresses certificate in SSL_CTX, client authentication
* Test 3 = app pre-compresses certificate in SSL_CTX, but it's unused due to prefs
*/
/* Compression helper */
static int ssl_comp_cert(SSL *ssl, int alg)
{
unsigned char *comp_data = NULL;
size_t comp_len = 0;
size_t orig_len = 0;
int retval = 0;
if (!TEST_size_t_gt(comp_len = SSL_get1_compressed_cert(ssl, alg, &comp_data, &orig_len), 0))
goto err;
if (!TEST_true(SSL_set1_compressed_cert(ssl, alg, comp_data, comp_len, orig_len)))
goto err;
retval = alg;
err:
OPENSSL_free(comp_data);
return retval;
}
static void cert_comp_info_cb(const SSL *s, int where, int ret)
{
int *seen = (int*)SSL_get_app_data(s);
if (SSL_is_server(s)) {
/* TLS_ST_SR_COMP_CERT */
if (!strcmp(SSL_state_string(s), "TRCCC") && seen != NULL)
*seen = 1;
} else {
/* TLS_ST_CR_COMP_CERT */
if (!strcmp(SSL_state_string(s), "TRSCC") && seen != NULL)
*seen = 1;
}
}
static int test_ssl_cert_comp(int test)
{
SSL_CTX *cctx = NULL, *sctx = NULL;
SSL *clientssl = NULL, *serverssl = NULL;
int testresult = 0;
int expected_client = TLSEXT_comp_cert_none;
int expected_server = TLSEXT_comp_cert_none;
int client_seen = 0;
int server_seen = 0;
/* reverse default order */
int server_pref[] = { TLSEXT_comp_cert_zstd, TLSEXT_comp_cert_zlib, TLSEXT_comp_cert_brotli };
/* default order */
int client_pref[] = { TLSEXT_comp_cert_brotli, TLSEXT_comp_cert_zlib, TLSEXT_comp_cert_zstd };
/* one of these *must* be defined! */
#ifndef OPENSSL_NO_BROTLI
expected_server = TLSEXT_comp_cert_brotli;
expected_client = TLSEXT_comp_cert_brotli;
#endif
#ifndef OPENSSL_NO_ZLIB
expected_server = TLSEXT_comp_cert_zlib;
if (expected_client == TLSEXT_comp_cert_none)
expected_client = TLSEXT_comp_cert_zlib;
#endif
#ifndef OPENSSL_NO_ZSTD
expected_server = TLSEXT_comp_cert_zstd;
if (expected_client == TLSEXT_comp_cert_none)
expected_client = TLSEXT_comp_cert_zstd;
#endif
/* if there's only one comp algorithm, pref won't do much */
if (test == 3 && expected_client == expected_server) {
TEST_info("Only one compression algorithm configured");
return 1;
}
if (!TEST_true(create_ssl_ctx_pair(NULL, TLS_server_method(),
TLS_client_method(),
TLS1_3_VERSION, 0,
&sctx, &cctx, cert, privkey)))
goto end;
if (test == 3) {
server_pref[0] = expected_server;
server_pref[1] = expected_client;
if (!TEST_true(SSL_CTX_set1_cert_comp_preference(sctx, server_pref, 2)))
goto end;
client_pref[0] = expected_client;
if (!TEST_true(SSL_CTX_set1_cert_comp_preference(cctx, client_pref, 1)))
goto end;
} else {
if (!TEST_true(SSL_CTX_set1_cert_comp_preference(sctx, server_pref, OSSL_NELEM(server_pref))))
goto end;
if (!TEST_true(SSL_CTX_set1_cert_comp_preference(cctx, client_pref, OSSL_NELEM(client_pref))))
goto end;
}
if (test == 2) {
/* Use callbacks from test_client_cert_cb() */
SSL_CTX_set_client_cert_cb(cctx, client_cert_cb);
SSL_CTX_set_verify(sctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb);
}
if (test == 1 || test== 2 || test == 3) {
if (!TEST_true(SSL_CTX_compress_certs(sctx, expected_server)))
goto end;
}
if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
NULL, NULL)))
goto end;
if (!TEST_true(SSL_set_app_data(clientssl, &client_seen)))
goto end;
if (!TEST_true(SSL_set_app_data(serverssl, &server_seen)))
goto end;
SSL_set_info_callback(clientssl, cert_comp_info_cb);
SSL_set_info_callback(serverssl, cert_comp_info_cb);
if (test == 0) {
if (!TEST_int_eq(ssl_comp_cert(serverssl, expected_server), expected_server))
goto end;
}
if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)))
goto end;
if (test == 3) {
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(serverssl);
/* expect that the pre-compressed cert won't be used */
if (!TEST_int_eq(sc->cert->key->cert_comp_used, 0))
goto end;
if (!TEST_false(*(int*)SSL_get_app_data(clientssl)))
goto end;
} else {
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(serverssl);
if (!TEST_int_gt(sc->cert->key->cert_comp_used, 0))
goto end;
if (!TEST_true(*(int*)SSL_get_app_data(clientssl)))
goto end;
}
if (test == 2) {
/* Only for client auth */
if (!TEST_true(*(int*)SSL_get_app_data(serverssl)))
goto end;
}
testresult = 1;
end:
SSL_free(serverssl);
SSL_free(clientssl);
SSL_CTX_free(sctx);
SSL_CTX_free(cctx);
return testresult;
}
#endif
OPT_TEST_DECLARE_USAGE("certdir\n")
int setup_tests(void)
{
#if !defined(OSSL_NO_USEABLE_TLS1_3)
if (!test_skip_common_options()) {
TEST_error("Error parsing test options\n");
return 0;
}
if (!TEST_ptr(certsdir = test_get_argument(0)))
return 0;
cert = test_mk_file_path(certsdir, "servercert.pem");
if (cert == NULL)
goto err;
privkey = test_mk_file_path(certsdir, "serverkey.pem");
if (privkey == NULL)
goto err;
ADD_ALL_TESTS(test_ssl_cert_comp, 4);
return 1;
err:
OPENSSL_free(cert);
OPENSSL_free(privkey);
return 0;
#else
return 1;
#endif
}
void cleanup_tests(void)
{
#if !defined(OSSL_NO_USEABLE_TLS1_3)
OPENSSL_free(cert);
OPENSSL_free(privkey);
#endif
}

View File

@ -67,6 +67,7 @@ static EXT_LIST ext_list[] = {
EXT_ENTRY(key_share),
EXT_ENTRY(cookie),
EXT_ENTRY(cryptopro_bug),
EXT_ENTRY(compress_certificate),
EXT_ENTRY(early_data),
EXT_ENTRY(certificate_authorities),
EXT_ENTRY(padding),

View File

@ -695,6 +695,14 @@ static int configure_handshake_ctx(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
server2_ctx_data, client_ctx_data))
goto err;
#endif /* !OPENSSL_NO_SRP */
#ifndef OPENSSL_NO_COMP_ALG
if (test->compress_certificates) {
if (!TEST_true(SSL_CTX_compress_certs(server_ctx, 0)))
goto err;
if (server2_ctx != NULL && !TEST_true(SSL_CTX_compress_certs(server2_ctx, 0)))
goto err;
}
#endif
return 1;
err:
return 0;

View File

@ -446,6 +446,7 @@ const char *ssl_ct_validation_name(ssl_ct_validation_t mode)
IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, resumption_expected)
IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_SERVER_CONF, server, broken_session_ticket)
IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, use_sctp)
IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, compress_certificates)
IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, enable_client_sctp_label_bug)
IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, enable_server_sctp_label_bug)
@ -686,6 +687,7 @@ static const ssl_test_ctx_option ssl_test_ctx_options[] = {
{ "ExpectedClientSignType", &parse_expected_client_sign_type },
{ "ExpectedClientCANames", &parse_expected_client_ca_names },
{ "UseSCTP", &parse_test_use_sctp },
{ "CompressCertificates", &parse_test_compress_certificates },
{ "EnableClientSCTPLabelBug", &parse_test_enable_client_sctp_label_bug },
{ "EnableServerSCTPLabelBug", &parse_test_enable_server_sctp_label_bug },
{ "ExpectedCipher", &parse_test_expected_cipher },

View File

@ -218,6 +218,8 @@ typedef struct {
STACK_OF(X509_NAME) *expected_client_ca_names;
/* Whether to use SCTP for the transport */
int use_sctp;
/* Whether to pre-compress server certificates */
int compress_certificates;
/* Enable SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG on client side */
int enable_client_sctp_label_bug;
/* Enable SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG on server side */

View File

@ -0,0 +1,295 @@
#! /usr/bin/env perl
# Copyright 2015-2020 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
use strict;
use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file srctop_dir bldtop_dir/;
use OpenSSL::Test::Utils;
use File::Temp qw(tempfile);
use TLSProxy::Proxy;
use checkhandshake qw(checkhandshake @handmessages @extensions);
my $test_name = "test_tls13certcomp";
setup($test_name);
plan skip_all => "TLSProxy isn't usable on $^O"
if $^O =~ /^(VMS)$/;
plan skip_all => "$test_name needs the dynamic engine feature enabled"
if disabled("engine") || disabled("dynamic-engine");
plan skip_all => "$test_name needs the sock feature enabled"
if disabled("sock");
plan skip_all => "$test_name needs TLSv1.3 enabled"
if disabled("tls1_3");
plan skip_all => "$test_name needs EC enabled"
if disabled("ec");
plan skip_all => "$test_name needs compression and algorithms enabled"
if disabled("comp") || (disabled("brotli") && disabled("zlib") && disabled("zstd"));
@handmessages = (
[TLSProxy::Message::MT_CLIENT_HELLO,
checkhandshake::ALL_HANDSHAKES],
[TLSProxy::Message::MT_SERVER_HELLO,
checkhandshake::ALL_HANDSHAKES],
[TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS,
checkhandshake::ALL_HANDSHAKES],
[TLSProxy::Message::MT_CERTIFICATE_REQUEST,
checkhandshake::CERT_COMP_CLI_HANDSHAKE | checkhandshake::CERT_COMP_BOTH_HANDSHAKE],
[TLSProxy::Message::MT_CERTIFICATE,
checkhandshake::ALL_HANDSHAKES & ~(checkhandshake::CERT_COMP_SRV_HANDSHAKE | checkhandshake::CERT_COMP_BOTH_HANDSHAKE)],
[TLSProxy::Message::MT_COMPRESSED_CERTIFICATE,
checkhandshake::CERT_COMP_SRV_HANDSHAKE | checkhandshake::CERT_COMP_BOTH_HANDSHAKE],
[TLSProxy::Message::MT_CERTIFICATE_VERIFY,
checkhandshake::ALL_HANDSHAKES],
[TLSProxy::Message::MT_FINISHED,
checkhandshake::ALL_HANDSHAKES],
[TLSProxy::Message::MT_COMPRESSED_CERTIFICATE,
checkhandshake::CERT_COMP_CLI_HANDSHAKE | checkhandshake::CERT_COMP_BOTH_HANDSHAKE],
[TLSProxy::Message::MT_CERTIFICATE_VERIFY,
checkhandshake::CERT_COMP_CLI_HANDSHAKE | checkhandshake::CERT_COMP_BOTH_HANDSHAKE],
[TLSProxy::Message::MT_FINISHED,
checkhandshake::ALL_HANDSHAKES],
[0, 0]
);
@extensions = (
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME,
TLSProxy::Message::CLIENT,
checkhandshake::SERVER_NAME_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST,
TLSProxy::Message::CLIENT,
checkhandshake::STATUS_REQUEST_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ALPN,
TLSProxy::Message::CLIENT,
checkhandshake::ALPN_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SCT,
TLSProxy::Message::CLIENT,
checkhandshake::SCT_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ENCRYPT_THEN_MAC,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EXTENDED_MASTER_SECRET,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SESSION_TICKET,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK_KEX_MODES,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK,
TLSProxy::Message::CLIENT,
checkhandshake::PSK_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_POST_HANDSHAKE_AUTH,
TLSProxy::Message::CLIENT,
checkhandshake::POST_HANDSHAKE_AUTH_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_COMPRESS_CERTIFICATE,
TLSProxy::Message::CLIENT,
checkhandshake::CERT_COMP_CLI_EXTENSION],
[TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS,
TLSProxy::Message::SERVER,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
TLSProxy::Message::SERVER,
checkhandshake::KEY_SHARE_HRR_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME,
TLSProxy::Message::CLIENT,
checkhandshake::SERVER_NAME_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST,
TLSProxy::Message::CLIENT,
checkhandshake::STATUS_REQUEST_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ALPN,
TLSProxy::Message::CLIENT,
checkhandshake::ALPN_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SCT,
TLSProxy::Message::CLIENT,
checkhandshake::SCT_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ENCRYPT_THEN_MAC,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EXTENDED_MASTER_SECRET,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SESSION_TICKET,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK_KEX_MODES,
TLSProxy::Message::CLIENT,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK,
TLSProxy::Message::CLIENT,
checkhandshake::PSK_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_POST_HANDSHAKE_AUTH,
TLSProxy::Message::CLIENT,
checkhandshake::POST_HANDSHAKE_AUTH_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_COMPRESS_CERTIFICATE,
TLSProxy::Message::CLIENT,
checkhandshake::CERT_COMP_CLI_EXTENSION],
[TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS,
TLSProxy::Message::SERVER,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
TLSProxy::Message::SERVER,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_PSK,
TLSProxy::Message::SERVER,
checkhandshake::PSK_SRV_EXTENSION],
[TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_SERVER_NAME,
TLSProxy::Message::SERVER,
checkhandshake::SERVER_NAME_SRV_EXTENSION],
[TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_ALPN,
TLSProxy::Message::SERVER,
checkhandshake::ALPN_SRV_EXTENSION],
[TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_SUPPORTED_GROUPS,
TLSProxy::Message::SERVER,
checkhandshake::SUPPORTED_GROUPS_SRV_EXTENSION],
[TLSProxy::Message::MT_CERTIFICATE_REQUEST, TLSProxy::Message::EXT_SIG_ALGS,
TLSProxy::Message::SERVER,
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CERTIFICATE_REQUEST, TLSProxy::Message::EXT_COMPRESS_CERTIFICATE,
TLSProxy::Message::SERVER,
checkhandshake::CERT_COMP_SRV_EXTENSION],
[TLSProxy::Message::MT_CERTIFICATE, TLSProxy::Message::EXT_STATUS_REQUEST,
TLSProxy::Message::SERVER,
checkhandshake::STATUS_REQUEST_SRV_EXTENSION],
[TLSProxy::Message::MT_CERTIFICATE, TLSProxy::Message::EXT_SCT,
TLSProxy::Message::SERVER,
checkhandshake::SCT_SRV_EXTENSION],
[0,0,0,0]
);
my $proxy = TLSProxy::Proxy->new(
undef,
cmdstr(app(["openssl"]), display => 1),
srctop_file("apps", "server.pem"),
(!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
);
#Test 1: Client sends cert comp, but no client auth
$proxy->serverconnects(2);
$proxy->clear();
$proxy->serverflags("-no_tx_cert_comp -no_rx_cert_comp");
# One final skip check
$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
plan tests => 8;
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
| checkhandshake::CERT_COMP_CLI_EXTENSION,
"Client supports certificate compression");
#Test 2: Server sends cert comp, no client auth
$proxy->clear();
$proxy->clientflags("-no_tx_cert_comp -no_rx_cert_comp");
$proxy->serverflags("-cert_comp");
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
| checkhandshake::CERT_COMP_SRV_EXTENSION,
"Server supports certificate compression, but no client auth");
#Test 3: Both send cert comp, no client auth
$proxy->clear();
$proxy->serverflags("-cert_comp");
$proxy->start();
checkhandshake($proxy, checkhandshake::CERT_COMP_SRV_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
| checkhandshake::CERT_COMP_CLI_EXTENSION
| checkhandshake::CERT_COMP_SRV_EXTENSION,
"Both support certificate compression, but no client auth");
#Test 4: Both send cert comp, with client auth
$proxy->clear();
$proxy->clientflags("-cert ".srctop_file("apps", "server.pem"));
$proxy->serverflags("-Verify 5 -cert_comp");
$proxy->start();
checkhandshake($proxy, checkhandshake::CERT_COMP_BOTH_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
| checkhandshake::CERT_COMP_CLI_EXTENSION
| checkhandshake::CERT_COMP_SRV_EXTENSION,
"Both support certificate compression, with client auth");
#Test 5: Client-to-server-only certificate compression, with client auth
$proxy->clear();
$proxy->clientflags("-no_rx_cert_comp -cert ".srctop_file("apps", "server.pem"));
$proxy->serverflags("-no_tx_cert_comp -Verify 5 -cert_comp");
$proxy->start();
checkhandshake($proxy, checkhandshake::CERT_COMP_CLI_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
| checkhandshake::CERT_COMP_SRV_EXTENSION,
"Client-to-server-only certificate compression, with client auth");
#Test 6: Server-to-client-only certificate compression
$proxy->clear();
$proxy->clientflags("-no_tx_cert_comp");
$proxy->serverflags("-no_rx_cert_comp -cert_comp");
$proxy->start();
checkhandshake($proxy, checkhandshake::CERT_COMP_SRV_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
| checkhandshake::CERT_COMP_CLI_EXTENSION,
"Server-to-client-only certificate compression");
#Test 7: Neither side wants to send a compressed cert, but will accept one
$proxy->clear();
$proxy->clientflags("-no_tx_cert_comp");
$proxy->serverflags("-no_tx_cert_comp -cert_comp");
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
| checkhandshake::CERT_COMP_CLI_EXTENSION
| checkhandshake::CERT_COMP_SRV_EXTENSION,
"Accept but not send compressed certificates");
#Test 8: Neither side wants to receive a compressed cert, but will send one
$proxy->clear();
$proxy->clientflags("-no_rx_cert_comp");
$proxy->serverflags("-no_rx_cert_comp -cert_comp");
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS,
"Send but not accept compressed certificates");

View File

@ -187,8 +187,8 @@ my $proxy = TLSProxy::Proxy->new(
#Test 1: First get a session
(undef, my $session) = tempfile();
$proxy->clientflags("-sess_out ".$session);
$proxy->serverflags("-servername localhost");
$proxy->clientflags("-no_rx_cert_comp -sess_out ".$session);
$proxy->serverflags("-no_rx_cert_comp -servername localhost");
$proxy->sessionfile($session);
$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
plan tests => 11;
@ -197,7 +197,7 @@ ok(TLSProxy::Message->success(), "Initial connection");
#Test 2: Attempt a resume with no kex modes extension. Should fail (server
# MUST abort handshake with pre_shared key and no psk_kex_modes)
$proxy->clear();
$proxy->clientflags("-sess_in ".$session);
$proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
my $testtype = DELETE_EXTENSION;
$proxy->filter(\&modify_kex_modes_filter);
$proxy->start();
@ -206,7 +206,7 @@ ok(TLSProxy::Message->fail(), "Resume with no kex modes");
#Test 3: Attempt a resume with empty kex modes extension. Should fail (empty
# extension is invalid)
$proxy->clear();
$proxy->clientflags("-sess_in ".$session);
$proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
$testtype = EMPTY_EXTENSION;
$proxy->start();
ok(TLSProxy::Message->fail(), "Resume with empty kex modes");
@ -214,8 +214,8 @@ ok(TLSProxy::Message->fail(), "Resume with empty kex modes");
#Test 4: Attempt a resume with non-dhe kex mode only. Should resume without a
# key_share
$proxy->clear();
$proxy->clientflags("-allow_no_dhe_kex -sess_in ".$session);
$proxy->serverflags("-allow_no_dhe_kex");
$proxy->clientflags("-no_rx_cert_comp -allow_no_dhe_kex -sess_in ".$session);
$proxy->serverflags("-no_rx_cert_comp -allow_no_dhe_kex");
$testtype = NON_DHE_KEX_MODE_ONLY;
$proxy->start();
checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
@ -227,7 +227,7 @@ checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
#Test 5: Attempt a resume with dhe kex mode only. Should resume with a key_share
$proxy->clear();
$proxy->clientflags("-sess_in ".$session);
$proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
$testtype = DHE_KEX_MODE_ONLY;
$proxy->start();
checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
@ -241,7 +241,7 @@ checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
#Test 6: Attempt a resume with only unrecognised kex modes. Should not resume
# but rather fall back to full handshake
$proxy->clear();
$proxy->clientflags("-sess_in ".$session);
$proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
$testtype = UNKNOWN_KEX_MODES;
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
@ -254,7 +254,7 @@ checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
#Test 7: Attempt a resume with both non-dhe and dhe kex mode. Should resume with
# a key_share
$proxy->clear();
$proxy->clientflags("-sess_in ".$session);
$proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
$testtype = BOTH_KEX_MODES;
$proxy->start();
checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
@ -268,8 +268,8 @@ checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
#Test 8: Attempt a resume with both non-dhe and dhe kex mode, but unacceptable
# initial key_share. Should resume with a key_share following an HRR
$proxy->clear();
$proxy->clientflags("-sess_in ".$session);
$proxy->serverflags("-curves P-256");
$proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
$proxy->serverflags("-no_rx_cert_comp -curves P-256");
$testtype = BOTH_KEX_MODES;
$proxy->start();
checkhandshake($proxy, checkhandshake::HRR_RESUME_HANDSHAKE,
@ -284,8 +284,8 @@ checkhandshake($proxy, checkhandshake::HRR_RESUME_HANDSHAKE,
#Test 9: Attempt a resume with dhe kex mode only and an unacceptable initial
# key_share. Should resume with a key_share following an HRR
$proxy->clear();
$proxy->clientflags("-sess_in ".$session);
$proxy->serverflags("-curves P-256");
$proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
$proxy->serverflags("-no_rx_cert_comp -curves P-256");
$testtype = DHE_KEX_MODE_ONLY;
$proxy->start();
checkhandshake($proxy, checkhandshake::HRR_RESUME_HANDSHAKE,
@ -301,8 +301,8 @@ checkhandshake($proxy, checkhandshake::HRR_RESUME_HANDSHAKE,
# initial key_share and no overlapping groups. Should resume without a
# key_share
$proxy->clear();
$proxy->clientflags("-allow_no_dhe_kex -curves P-384 -sess_in ".$session);
$proxy->serverflags("-allow_no_dhe_kex -curves P-256");
$proxy->clientflags("-no_rx_cert_comp -allow_no_dhe_kex -curves P-384 -sess_in ".$session);
$proxy->serverflags("-no_rx_cert_comp -allow_no_dhe_kex -curves P-256");
$testtype = BOTH_KEX_MODES;
$proxy->start();
checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
@ -315,8 +315,8 @@ checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
#Test 11: Attempt a resume with dhe kex mode only, unacceptable
# initial key_share and no overlapping groups. Should fail
$proxy->clear();
$proxy->clientflags("-curves P-384 -sess_in ".$session);
$proxy->serverflags("-curves P-256");
$proxy->clientflags("-no_rx_cert_comp -curves P-384 -sess_in ".$session);
$proxy->serverflags("-no_rx_cert_comp -curves P-256");
$testtype = DHE_KEX_MODE_ONLY;
$proxy->start();
ok(TLSProxy::Message->fail(), "Resume with dhe kex mode, no overlapping groups");

View File

@ -203,7 +203,7 @@ my $proxy = TLSProxy::Proxy->new(
#Test 1: Check we get all the right messages for a default handshake
(undef, my $session) = tempfile();
$proxy->serverconnects(2);
$proxy->clientflags("-sess_out ".$session);
$proxy->clientflags("-no_rx_cert_comp -sess_out ".$session);
$proxy->sessionfile($session);
$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
plan tests => 17;
@ -213,7 +213,7 @@ checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
#Test 2: Resumption handshake
$proxy->clearClient();
$proxy->clientflags("-sess_in ".$session);
$proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
$proxy->clientstart();
checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
(checkhandshake::DEFAULT_EXTENSIONS
@ -226,7 +226,7 @@ SKIP: {
if disabled("ct") || disabled("ec") || disabled("ocsp");
#Test 3: A status_request handshake (client request only)
$proxy->clear();
$proxy->clientflags("-status");
$proxy->clientflags("-no_rx_cert_comp -status");
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
@ -235,7 +235,8 @@ SKIP: {
#Test 4: A status_request handshake (server support only)
$proxy->clear();
$proxy->serverflags("-status_file "
$proxy->clientflags("-no_rx_cert_comp");
$proxy->serverflags("-no_rx_cert_comp -status_file "
.srctop_file("test", "recipes", "ocsp-response.der"));
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
@ -244,8 +245,8 @@ SKIP: {
#Test 5: A status_request handshake (client and server)
$proxy->clear();
$proxy->clientflags("-status");
$proxy->serverflags("-status_file "
$proxy->clientflags("-no_rx_cert_comp -status");
$proxy->serverflags("-no_rx_cert_comp -status_file "
.srctop_file("test", "recipes", "ocsp-response.der"));
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
@ -256,9 +257,9 @@ SKIP: {
#Test 6: A status_request handshake (client and server) with client auth
$proxy->clear();
$proxy->clientflags("-status -enable_pha -cert "
$proxy->clientflags("-no_rx_cert_comp -status -enable_pha -cert "
.srctop_file("apps", "server.pem"));
$proxy->serverflags("-Verify 5 -status_file "
$proxy->serverflags("-no_rx_cert_comp -Verify 5 -status_file "
.srctop_file("test", "recipes", "ocsp-response.der"));
$proxy->start();
checkhandshake($proxy, checkhandshake::CLIENT_AUTH_HANDSHAKE,
@ -271,8 +272,8 @@ SKIP: {
#Test 7: A client auth handshake
$proxy->clear();
$proxy->clientflags("-enable_pha -cert ".srctop_file("apps", "server.pem"));
$proxy->serverflags("-Verify 5");
$proxy->clientflags("-no_rx_cert_comp -enable_pha -cert ".srctop_file("apps", "server.pem"));
$proxy->serverflags("-no_rx_cert_comp -Verify 5");
$proxy->start();
checkhandshake($proxy, checkhandshake::CLIENT_AUTH_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS |
@ -281,7 +282,7 @@ checkhandshake($proxy, checkhandshake::CLIENT_AUTH_HANDSHAKE,
#Test 8: Server name handshake (no client request)
$proxy->clear();
$proxy->clientflags("-noservername");
$proxy->clientflags("-no_rx_cert_comp -noservername");
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
@ -290,8 +291,8 @@ checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
#Test 9: Server name handshake (server support only)
$proxy->clear();
$proxy->clientflags("-noservername");
$proxy->serverflags("-servername testhost");
$proxy->clientflags("-no_rx_cert_comp -noservername");
$proxy->serverflags("-no_rx_cert_comp -servername testhost");
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
@ -300,8 +301,8 @@ checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
#Test 10: Server name handshake (client and server)
$proxy->clear();
$proxy->clientflags("-servername testhost");
$proxy->serverflags("-servername testhost");
$proxy->clientflags("-no_rx_cert_comp -servername testhost");
$proxy->serverflags("-no_rx_cert_comp -servername testhost");
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
@ -310,7 +311,7 @@ checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
#Test 11: ALPN handshake (client request only)
$proxy->clear();
$proxy->clientflags("-alpn test");
$proxy->clientflags("-no_rx_cert_comp -alpn test");
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
@ -319,7 +320,8 @@ checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
#Test 12: ALPN handshake (server support only)
$proxy->clear();
$proxy->serverflags("-alpn test");
$proxy->clientflags("-no_rx_cert_comp");
$proxy->serverflags("-no_rx_cert_comp -alpn test");
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS,
@ -327,8 +329,8 @@ checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
#Test 13: ALPN handshake (client and server)
$proxy->clear();
$proxy->clientflags("-alpn test");
$proxy->serverflags("-alpn test");
$proxy->clientflags("-no_rx_cert_comp -alpn test");
$proxy->serverflags("-no_rx_cert_comp -alpn test");
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
@ -343,8 +345,8 @@ SKIP: {
#Test 14: SCT handshake (client request only)
$proxy->clear();
#Note: -ct also sends status_request
$proxy->clientflags("-ct");
$proxy->serverflags("-status_file "
$proxy->clientflags("-no_rx_cert_comp -ct");
$proxy->serverflags("-no_rx_cert_comp -status_file "
.srctop_file("test", "recipes", "ocsp-response.der")
." -serverinfo ".srctop_file("test", "serverinfo2.pem"));
$proxy->start();
@ -359,7 +361,8 @@ SKIP: {
#Test 15: HRR Handshake
$proxy->clear();
$proxy->serverflags("-curves P-256");
$proxy->clientflags("-no_rx_cert_comp");
$proxy->serverflags("-no_rx_cert_comp -curves P-256");
$proxy->start();
checkhandshake($proxy, checkhandshake::HRR_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS
@ -368,8 +371,8 @@ checkhandshake($proxy, checkhandshake::HRR_HANDSHAKE,
#Test 16: Resumption handshake with HRR
$proxy->clear();
$proxy->clientflags("-sess_in ".$session);
$proxy->serverflags("-curves P-256");
$proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
$proxy->serverflags("-no_rx_cert_comp -curves P-256");
$proxy->start();
checkhandshake($proxy, checkhandshake::HRR_RESUME_HANDSHAKE,
(checkhandshake::DEFAULT_EXTENSIONS
@ -380,7 +383,7 @@ checkhandshake($proxy, checkhandshake::HRR_RESUME_HANDSHAKE,
#Test 17: Acceptable but non preferred key_share
$proxy->clear();
$proxy->clientflags("-curves P-256");
$proxy->clientflags("-no_rx_cert_comp -curves P-256");
$proxy->start();
checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS

View File

@ -42,7 +42,7 @@ if (defined $ENV{SSL_TESTS}) {
@conf_srcs = glob(srctop_file("test", "ssl-tests", "*.cnf.in"));
# We hard-code the number of tests to double-check that the globbing above
# finds all files as expected.
plan tests => 31;
plan tests => 32;
}
map { s/;.*// } @conf_srcs if $^O eq "VMS";
my @conf_files = map { basename($_, ".in") } @conf_srcs;
@ -93,6 +93,7 @@ my %conf_dependent_tests = (
"27-ticket-appdata.cnf" => !$is_default_tls,
"28-seclevel.cnf" => disabled("tls1_2") || $no_ec,
"30-extended-master-secret.cnf" => disabled("tls1_2"),
"32-compressed-certificate.cnf" => disabled("comp") || disabled("tls1_3"),
);
# Add your test here if it should be skipped for some compile-time
@ -127,7 +128,8 @@ my %skip = (
"25-cipher.cnf" => disabled("ec") || disabled("tls1_2"),
"26-tls13_client_auth.cnf" => disabled("tls1_3") || ($no_ec && $no_dh),
"29-dtls-sctp-label-bug.cnf" => disabled("sctp") || disabled("sock"),
"31-quic.cnf" => $no_quic || $no_ec
"31-quic.cnf" => $no_quic || $no_ec,
"32-compressed-certificate.cnf" => disabled("comp") || disabled("tls1_3"),
);
foreach my $conf (@conf_files) {

View File

@ -0,0 +1,24 @@
#! /usr/bin/env perl
# Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
use OpenSSL::Test::Utils;
use OpenSSL::Test qw/:DEFAULT srctop_dir bldtop_dir/;
BEGIN {
setup("test_cert_comp");
}
use lib srctop_dir('Configurations');
use lib bldtop_dir('.');
plan skip_all => "Certificate compression is disabled in this OpenSSL build"
if disabled("comp") || (disabled("brotli") && disabled("zstd") && disabled("zlib"));
plan tests => 1;
ok(run(test(["cert_comp_test", srctop_dir("test", "certs")])), "running cert_comp_test");

View File

@ -0,0 +1,244 @@
# Generated with generate_ssl_tests.pl
num_tests = 8
test-0 = 0-no-compressed-certificates
test-1 = 1-server-compressed-certificates
test-2 = 2-client-compressed-certificates
test-3 = 3-both-compressed-certificates
test-4 = 4-no-compressed-certificates-mtls
test-5 = 5-server-compressed-certificates-mtls
test-6 = 6-client-compressed-certificates-mtls
test-7 = 7-both-compressed-certificates-mtls
# ===========================================================
[0-no-compressed-certificates]
ssl_conf = 0-no-compressed-certificates-ssl
[0-no-compressed-certificates-ssl]
server = 0-no-compressed-certificates-server
client = 0-no-compressed-certificates-client
[0-no-compressed-certificates-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
Options = -TxCertificateCompression,-RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
[0-no-compressed-certificates-client]
CipherString = DEFAULT
MinProtocol = TLSv1.3
Options = -TxCertificateCompression,-RxCertificateCompression
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-0]
CompressCertificates = Yes
ExpectedResult = Success
# ===========================================================
[1-server-compressed-certificates]
ssl_conf = 1-server-compressed-certificates-ssl
[1-server-compressed-certificates-ssl]
server = 1-server-compressed-certificates-server
client = 1-server-compressed-certificates-client
[1-server-compressed-certificates-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
Options = TxCertificateCompression,RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
[1-server-compressed-certificates-client]
CipherString = DEFAULT
MinProtocol = TLSv1.3
Options = -TxCertificateCompression,-RxCertificateCompression
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-1]
CompressCertificates = Yes
ExpectedResult = Success
# ===========================================================
[2-client-compressed-certificates]
ssl_conf = 2-client-compressed-certificates-ssl
[2-client-compressed-certificates-ssl]
server = 2-client-compressed-certificates-server
client = 2-client-compressed-certificates-client
[2-client-compressed-certificates-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
Options = -TxCertificateCompression,-RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
[2-client-compressed-certificates-client]
CipherString = DEFAULT
MinProtocol = TLSv1.3
Options = TxCertificateCompression,RxCertificateCompression
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-2]
CompressCertificates = Yes
ExpectedResult = Success
# ===========================================================
[3-both-compressed-certificates]
ssl_conf = 3-both-compressed-certificates-ssl
[3-both-compressed-certificates-ssl]
server = 3-both-compressed-certificates-server
client = 3-both-compressed-certificates-client
[3-both-compressed-certificates-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
Options = TxCertificateCompression,RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
[3-both-compressed-certificates-client]
CipherString = DEFAULT
MinProtocol = TLSv1.3
Options = TxCertificateCompression,RxCertificateCompression
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-3]
CompressCertificates = Yes
ExpectedResult = Success
# ===========================================================
[4-no-compressed-certificates-mtls]
ssl_conf = 4-no-compressed-certificates-mtls-ssl
[4-no-compressed-certificates-mtls-ssl]
server = 4-no-compressed-certificates-mtls-server
client = 4-no-compressed-certificates-mtls-client
[4-no-compressed-certificates-mtls-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
Options = -TxCertificateCompression,-RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
VerifyMode = Request
[4-no-compressed-certificates-mtls-client]
Certificate = ${ENV::TEST_CERTS_DIR}/ee-client-chain.pem
CipherString = DEFAULT
MinProtocol = TLSv1.3
Options = -TxCertificateCompression,-RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/ee-key.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-4]
CompressCertificates = Yes
ExpectedResult = Success
# ===========================================================
[5-server-compressed-certificates-mtls]
ssl_conf = 5-server-compressed-certificates-mtls-ssl
[5-server-compressed-certificates-mtls-ssl]
server = 5-server-compressed-certificates-mtls-server
client = 5-server-compressed-certificates-mtls-client
[5-server-compressed-certificates-mtls-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
Options = TxCertificateCompression,RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
VerifyMode = Request
[5-server-compressed-certificates-mtls-client]
Certificate = ${ENV::TEST_CERTS_DIR}/ee-client-chain.pem
CipherString = DEFAULT
MinProtocol = TLSv1.3
Options = -TxCertificateCompression,-RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/ee-key.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-5]
CompressCertificates = Yes
ExpectedResult = Success
# ===========================================================
[6-client-compressed-certificates-mtls]
ssl_conf = 6-client-compressed-certificates-mtls-ssl
[6-client-compressed-certificates-mtls-ssl]
server = 6-client-compressed-certificates-mtls-server
client = 6-client-compressed-certificates-mtls-client
[6-client-compressed-certificates-mtls-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
Options = -TxCertificateCompression,-RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
VerifyMode = Request
[6-client-compressed-certificates-mtls-client]
Certificate = ${ENV::TEST_CERTS_DIR}/ee-client-chain.pem
CipherString = DEFAULT
MinProtocol = TLSv1.3
Options = TxCertificateCompression,RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/ee-key.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-6]
CompressCertificates = Yes
ExpectedResult = Success
# ===========================================================
[7-both-compressed-certificates-mtls]
ssl_conf = 7-both-compressed-certificates-mtls-ssl
[7-both-compressed-certificates-mtls-ssl]
server = 7-both-compressed-certificates-mtls-server
client = 7-both-compressed-certificates-mtls-client
[7-both-compressed-certificates-mtls-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
Options = TxCertificateCompression,RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
VerifyMode = Request
[7-both-compressed-certificates-mtls-client]
Certificate = ${ENV::TEST_CERTS_DIR}/ee-client-chain.pem
CipherString = DEFAULT
MinProtocol = TLSv1.3
Options = TxCertificateCompression,RxCertificateCompression
PrivateKey = ${ENV::TEST_CERTS_DIR}/ee-key.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-7]
CompressCertificates = Yes
ExpectedResult = Success

View File

@ -0,0 +1,147 @@
# -*- mode: perl; -*-
# Copyright 2016-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
## SSL test configurations
package ssltests;
use OpenSSL::Test::Utils;
our @tests = ();
our @tests = (
{
name => "no-compressed-certificates",
server => {
"Options" => "-TxCertificateCompression,-RxCertificateCompression",
},
client => {
"Options" => "-TxCertificateCompression,-RxCertificateCompression",
"MinProtocol" => "TLSv1.3",
},
test => {
"ExpectedResult" => "Success",
"CompressCertificates" => "Yes",
},
},
{
name => "server-compressed-certificates",
server => {
"Options" => "TxCertificateCompression,RxCertificateCompression",
},
client => {
"Options" => "-TxCertificateCompression,-RxCertificateCompression",
"MinProtocol" => "TLSv1.3",
},
test => {
"ExpectedResult" => "Success",
"CompressCertificates" => "Yes",
},
},
{
name => "client-compressed-certificates",
server => {
"Options" => "-TxCertificateCompression,-RxCertificateCompression",
},
client => {
"Options" => "TxCertificateCompression,RxCertificateCompression",
"MinProtocol" => "TLSv1.3",
},
test => {
"ExpectedResult" => "Success",
"CompressCertificates" => "Yes",
},
},
{
name => "both-compressed-certificates",
server => {
"Options" => "TxCertificateCompression,RxCertificateCompression",
},
client => {
"Options" => "TxCertificateCompression,RxCertificateCompression",
"MinProtocol" => "TLSv1.3",
},
test => {
"ExpectedResult" => "Success",
"CompressCertificates" => "Yes",
},
},
{
name => "no-compressed-certificates-mtls",
server => {
"Options" => "-TxCertificateCompression,-RxCertificateCompression",
"VerifyCAFile" => test_pem("root-cert.pem"),
"VerifyMode" => "Request",
},
client => {
"Options" => "-TxCertificateCompression,-RxCertificateCompression",
"MinProtocol" => "TLSv1.3",
"Certificate" => test_pem("ee-client-chain.pem"),
"PrivateKey" => test_pem("ee-key.pem"),
},
test => {
"ExpectedResult" => "Success",
"CompressCertificates" => "Yes",
},
},
{
name => "server-compressed-certificates-mtls",
server => {
"Options" => "TxCertificateCompression,RxCertificateCompression",
"VerifyCAFile" => test_pem("root-cert.pem"),
"VerifyMode" => "Request",
},
client => {
"Options" => "-TxCertificateCompression,-RxCertificateCompression",
"MinProtocol" => "TLSv1.3",
"Certificate" => test_pem("ee-client-chain.pem"),
"PrivateKey" => test_pem("ee-key.pem"),
},
test => {
"ExpectedResult" => "Success",
"CompressCertificates" => "Yes",
},
},
{
name => "client-compressed-certificates-mtls",
server => {
"Options" => "-TxCertificateCompression,-RxCertificateCompression",
"VerifyCAFile" => test_pem("root-cert.pem"),
"VerifyMode" => "Request",
},
client => {
"Options" => "TxCertificateCompression,RxCertificateCompression",
"MinProtocol" => "TLSv1.3",
"Certificate" => test_pem("ee-client-chain.pem"),
"PrivateKey" => test_pem("ee-key.pem"),
},
test => {
"ExpectedResult" => "Success",
"CompressCertificates" => "Yes",
},
},
{
name => "both-compressed-certificates-mtls",
server => {
"Options" => "TxCertificateCompression,RxCertificateCompression",
"VerifyCAFile" => test_pem("root-cert.pem"),
"VerifyMode" => "Request",
},
client => {
"Options" => "TxCertificateCompression,RxCertificateCompression",
"MinProtocol" => "TLSv1.3",
"Certificate" => test_pem("ee-client-chain.pem"),
"PrivateKey" => test_pem("ee-key.pem"),
},
test => {
"ExpectedResult" => "Success",
"CompressCertificates" => "Yes",
},
},
);

View File

@ -7164,6 +7164,38 @@ static struct info_cb_states_st {
{SSL_CB_LOOP, "TWFIN"}, {SSL_CB_HANDSHAKE_DONE, NULL},
{SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "SSLOK"}, {SSL_CB_LOOP, "SSLOK"},
{SSL_CB_LOOP, "TRST"}, {SSL_CB_EXIT, NULL}, {0, NULL},
}, {
/* TLSv1.3 server, certificate compression, followed by resumption */
{SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "PINIT"},
{SSL_CB_LOOP, "PINIT"}, {SSL_CB_LOOP, "TRCH"}, {SSL_CB_LOOP, "TWSH"},
{SSL_CB_LOOP, "TWCCS"}, {SSL_CB_LOOP, "TWEE"}, {SSL_CB_LOOP, "TWSCC"},
{SSL_CB_LOOP, "TWSCV"}, {SSL_CB_LOOP, "TWFIN"}, {SSL_CB_LOOP, "TED"},
{SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "TED"}, {SSL_CB_LOOP, "TRFIN"},
{SSL_CB_HANDSHAKE_DONE, NULL}, {SSL_CB_LOOP, "TWST"},
{SSL_CB_LOOP, "TWST"}, {SSL_CB_EXIT, NULL}, {SSL_CB_ALERT, NULL},
{SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "PINIT"},
{SSL_CB_LOOP, "PINIT"}, {SSL_CB_LOOP, "TRCH"}, {SSL_CB_LOOP, "TWSH"},
{SSL_CB_LOOP, "TWCCS"}, {SSL_CB_LOOP, "TWEE"}, {SSL_CB_LOOP, "TWFIN"},
{SSL_CB_LOOP, "TED"}, {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "TED"},
{SSL_CB_LOOP, "TRFIN"}, {SSL_CB_HANDSHAKE_DONE, NULL},
{SSL_CB_LOOP, "TWST"}, {SSL_CB_EXIT, NULL}, {0, NULL},
}, {
/* TLSv1.3 client, certificate compression, followed by resumption */
{SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "PINIT"},
{SSL_CB_LOOP, "TWCH"}, {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "TWCH"},
{SSL_CB_LOOP, "TRSH"}, {SSL_CB_LOOP, "TREE"}, {SSL_CB_LOOP, "TRSCC"},
{SSL_CB_LOOP, "TRSCV"}, {SSL_CB_LOOP, "TRFIN"}, {SSL_CB_LOOP, "TWCCS"},
{SSL_CB_LOOP, "TWFIN"}, {SSL_CB_HANDSHAKE_DONE, NULL},
{SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "SSLOK"}, {SSL_CB_LOOP, "SSLOK"},
{SSL_CB_LOOP, "TRST"}, {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "SSLOK"},
{SSL_CB_LOOP, "SSLOK"}, {SSL_CB_LOOP, "TRST"}, {SSL_CB_EXIT, NULL},
{SSL_CB_ALERT, NULL}, {SSL_CB_HANDSHAKE_START, NULL},
{SSL_CB_LOOP, "PINIT"}, {SSL_CB_LOOP, "TWCH"}, {SSL_CB_EXIT, NULL},
{SSL_CB_LOOP, "TWCH"}, {SSL_CB_LOOP, "TRSH"}, {SSL_CB_LOOP, "TREE"},
{SSL_CB_LOOP, "TRFIN"}, {SSL_CB_LOOP, "TWCCS"}, {SSL_CB_LOOP, "TWFIN"},
{SSL_CB_HANDSHAKE_DONE, NULL}, {SSL_CB_EXIT, NULL},
{SSL_CB_LOOP, "SSLOK"}, {SSL_CB_LOOP, "SSLOK"}, {SSL_CB_LOOP, "TRST"},
{SSL_CB_EXIT, NULL}, {0, NULL},
}, {
{0, NULL},
}
@ -7221,6 +7253,8 @@ static void sslapi_info_callback(const SSL *s, int where, int ret)
* Test 3: TLSv1.3, client
* Test 4: TLSv1.3, server, early_data
* Test 5: TLSv1.3, client, early_data
* Test 6: TLSv1.3, server, compressed certificate
* Test 7: TLSv1.3, client, compressed certificate
*/
static int test_info_callback(int tst)
{
@ -7252,7 +7286,7 @@ static int test_info_callback(int tst)
info_cb_offset = tst;
#ifndef OSSL_NO_USABLE_TLS1_3
if (tst >= 4) {
if (tst >= 4 && tst < 6) {
SSL_SESSION *sess = NULL;
size_t written, readbytes;
unsigned char buf[80];
@ -7303,6 +7337,10 @@ static int test_info_callback(int tst)
*/
SSL_CTX_set_info_callback((tst % 2) == 0 ? sctx : cctx,
sslapi_info_callback);
if (tst >= 6) {
if (!SSL_CTX_compress_certs(sctx, 0))
goto end;
}
if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
&clientssl, NULL, NULL))
@ -10339,7 +10377,12 @@ int setup_tests(void)
#if !defined(OPENSSL_NO_SRP) && !defined(OPENSSL_NO_TLS1_2)
ADD_ALL_TESTS(test_srp, 6);
#endif
#if !defined(OPENSSL_NO_COMP_ALG)
/* Add compression case */
ADD_ALL_TESTS(test_info_callback, 8);
#else
ADD_ALL_TESTS(test_info_callback, 6);
#endif
ADD_ALL_TESTS(test_ssl_pending, 2);
ADD_ALL_TESTS(test_ssl_get_shared_ciphers, OSSL_NELEM(shared_ciphers_data));
ADD_ALL_TESTS(test_ticket_callbacks, 20);

View File

@ -524,3 +524,11 @@ SSL_client_hello_get_extension_order ? 3_2_0 EXIST::FUNCTION:
OSSL_QUIC_client_method ? 3_2_0 EXIST::FUNCTION:QUIC
OSSL_QUIC_client_thread_method ? 3_2_0 EXIST::FUNCTION:QUIC
OSSL_QUIC_server_method ? 3_2_0 EXIST::FUNCTION:QUIC
SSL_CTX_set1_cert_comp_preference ? 3_2_0 EXIST::FUNCTION:
SSL_set1_cert_comp_preference ? 3_2_0 EXIST::FUNCTION:
SSL_CTX_compress_certs ? 3_2_0 EXIST::FUNCTION:
SSL_compress_certs ? 3_2_0 EXIST::FUNCTION:
SSL_CTX_set1_compressed_cert ? 3_2_0 EXIST::FUNCTION:
SSL_set1_compressed_cert ? 3_2_0 EXIST::FUNCTION:
SSL_CTX_get1_compressed_cert ? 3_2_0 EXIST::FUNCTION:
SSL_get1_compressed_cert ? 3_2_0 EXIST::FUNCTION:

View File

@ -28,6 +28,7 @@ use constant {
MT_CLIENT_KEY_EXCHANGE => 16,
MT_FINISHED => 20,
MT_CERTIFICATE_STATUS => 22,
MT_COMPRESSED_CERTIFICATE => 25,
MT_NEXT_PROTO => 67
};
@ -59,6 +60,7 @@ my %message_type = (
MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange",
MT_FINISHED, "Finished",
MT_CERTIFICATE_STATUS, "CertificateStatus",
MT_COMPRESSED_CERTIFICATE, "CompressedCertificate",
MT_NEXT_PROTO, "NextProto"
);
@ -76,6 +78,7 @@ use constant {
EXT_PADDING => 21,
EXT_ENCRYPT_THEN_MAC => 22,
EXT_EXTENDED_MASTER_SECRET => 23,
EXT_COMPRESS_CERTIFICATE => 27,
EXT_SESSION_TICKET => 35,
EXT_KEY_SHARE => 51,
EXT_PSK => 41,

View File

@ -26,8 +26,11 @@ use constant {
EC_HANDSHAKE => 64,
HRR_HANDSHAKE => 128,
HRR_RESUME_HANDSHAKE => 256,
CERT_COMP_SRV_HANDSHAKE => 512,
CERT_COMP_CLI_HANDSHAKE => 1024,
CERT_COMP_BOTH_HANDSHAKE => 2048,
ALL_HANDSHAKES => 511
ALL_HANDSHAKES => 4095
};
use constant {
@ -54,7 +57,9 @@ use constant {
PSK_KEX_MODES_EXTENSION => 0x00040000,
KEY_SHARE_HRR_EXTENSION => 0x00080000,
SUPPORTED_GROUPS_SRV_EXTENSION => 0x00100000,
POST_HANDSHAKE_AUTH_CLI_EXTENSION => 0x00200000
POST_HANDSHAKE_AUTH_CLI_EXTENSION => 0x00200000,
CERT_COMP_CLI_EXTENSION => 0x00400000,
CERT_COMP_SRV_EXTENSION => 0x00800000
};
our @handmessages = ();