mirror of
https://github.com/openssl/openssl.git
synced 2025-03-31 20:10:45 +08:00
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:
parent
59d21298df
commit
b67cb09f8d
@ -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.
|
||||
|
2
NEWS.md
2
NEWS.md
@ -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
|
||||
|
@ -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: \
|
||||
|
@ -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},
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
160
doc/man3/SSL_CTX_set1_cert_comp_preference.pod
Normal file
160
doc/man3/SSL_CTX_set1_cert_comp_preference.pod
Normal 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
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
479
ssl/ssl_cert_comp.c
Normal 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
|
||||
}
|
@ -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 */
|
||||
|
@ -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"},
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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())))
|
||||
|
@ -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
281
test/cert_comp_test.c
Normal 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
|
||||
}
|
@ -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),
|
||||
|
@ -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;
|
||||
|
@ -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 },
|
||||
|
@ -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 */
|
||||
|
295
test/recipes/70-test_tls13certcomp.t
Normal file
295
test/recipes/70-test_tls13certcomp.t
Normal 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");
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
24
test/recipes/90-test_cert_comp.t
Normal file
24
test/recipes/90-test_cert_comp.t
Normal 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");
|
244
test/ssl-tests/32-compressed-certificate.cnf
Normal file
244
test/ssl-tests/32-compressed-certificate.cnf
Normal 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
|
||||
|
||||
|
147
test/ssl-tests/32-compressed-certificate.cnf.in
Normal file
147
test/ssl-tests/32-compressed-certificate.cnf.in
Normal 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",
|
||||
},
|
||||
},
|
||||
);
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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 = ();
|
||||
|
Loading…
x
Reference in New Issue
Block a user