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