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 {
| 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
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;
+}