TLS13: prepare for early data trial decryption
[metze/wireshark/wip.git] / epan / dissectors / packet-ssl-utils.c
index cb3f9ce53b1dd98f87330c945df39e7d33940767..81b7e17b711a4090f16375914f68ca4f68f97bfa 100644 (file)
@@ -9,19 +9,7 @@
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
 #include "config.h"
 #include <wsutil/strtoi.h>
 #include <wsutil/wsgcrypt.h>
 #include <wsutil/rsa.h>
-#include <ws_version_info.h>
+#include <version_info.h>
 #include "packet-ber.h"
 #include "packet-x509af.h"
 #include "packet-x509if.h"
 #include "packet-ssl-utils.h"
+#include "packet-ocsp.h"
 #include "packet-ssl.h"
 #include "packet-dtls.h"
 #if defined(HAVE_LIBGNUTLS)
@@ -100,6 +89,10 @@ const value_string ssl_versions[] = {
     { 0x7F12,               "TLS 1.3 (draft 18)" },
     { 0x7F13,               "TLS 1.3 (draft 19)" },
     { 0x7F14,               "TLS 1.3 (draft 20)" },
+    { 0x7F15,               "TLS 1.3 (draft 21)" },
+    { 0x7F16,               "TLS 1.3 (draft 22)" },
+    { 0x7F17,               "TLS 1.3 (draft 23)" },
+    { 0x7F18,               "TLS 1.3 (draft 24)" },
     { DTLSV1DOT0_OPENSSL_VERSION, "DTLS 1.0 (OpenSSL pre 0.9.8f)" },
     { DTLSV1DOT0_VERSION,   "DTLS 1.0" },
     { DTLSV1DOT2_VERSION,   "DTLS 1.2" },
@@ -1074,6 +1067,11 @@ static const value_string ssl_31_ciphersuite[] = {
     { 0xCCAC, "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256" },
     { 0xCCAD, "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256" },
     { 0xCCAE, "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256" },
+    /* https://tools.ietf.org/html/draft-ietf-tls-ecdhe-psk-aead */
+    { 0xD001, "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256" },
+    { 0xD002, "TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384" },
+    { 0xD003, "TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256" },
+    { 0xD005, "TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256" },
     /* https://tools.ietf.org/html/draft-ietf-tls-grease */
     { 0xDADA, "Reserved (GREASE)" },
     /* http://tools.ietf.org/html/draft-josefsson-salsa20-tls */
@@ -1202,16 +1200,20 @@ const value_string tls_hello_extension_types[] = {
     { SSL_HND_HELLO_EXT_EXTENDED_MASTER_SECRET, "extended_master_secret" }, /* RFC 7627 */
     { SSL_HND_HELLO_EXT_TOKEN_BINDING, "token_binding" }, /* https://tools.ietf.org/html/draft-ietf-tokbind-negotiation */
     { SSL_HND_HELLO_EXT_CACHED_INFO, "cached_info" }, /* RFC 7924 */
+    { SSL_HND_HELLO_EXT_QUIC_TRANSPORT_PARAMETERS, "quic_transports_parameters" }, /* https://tools.ietf.org/html/draft-ietf-quic-tls */
     { SSL_HND_HELLO_EXT_SESSION_TICKET_TLS, "SessionTicket TLS" }, /* RFC 4507 */
-    { SSL_HND_HELLO_EXT_KEY_SHARE, "key_share" }, /* TLS 1.3 https://tools.ietf.org/html/draft-ietf-tls-tls13 */
+    { SSL_HND_HELLO_EXT_KEY_SHARE_OLD, "Reserved (key_share)" }, /* https://tools.ietf.org/html/draft-ietf-tls-tls13-22 */
     { SSL_HND_HELLO_EXT_PRE_SHARED_KEY, "pre_shared_key" }, /* TLS 1.3 https://tools.ietf.org/html/draft-ietf-tls-tls13 */
     { SSL_HND_HELLO_EXT_EARLY_DATA, "early_data" }, /* TLS 1.3 https://tools.ietf.org/html/draft-ietf-tls-tls13 */
     { SSL_HND_HELLO_EXT_SUPPORTED_VERSIONS, "supported_versions" }, /* TLS 1.3 https://tools.ietf.org/html/draft-ietf-tls-tls13 */
     { SSL_HND_HELLO_EXT_COOKIE, "cookie" }, /* TLS 1.3 https://tools.ietf.org/html/draft-ietf-tls-tls13 */
     { SSL_HND_HELLO_EXT_PSK_KEY_EXCHANGE_MODES, "psk_key_exchange_modes" }, /* TLS 1.3 https://tools.ietf.org/html/draft-ietf-tls-tls13 */
+    { SSL_HND_HELLO_EXT_TICKET_EARLY_DATA_INFO, "ticket_early_data_info" }, /* draft-ietf-tls-tls13-18 (removed in -19) */
     { SSL_HND_HELLO_EXT_CERTIFICATE_AUTHORITIES, "certificate_authorities" }, /* https://tools.ietf.org/html/draft-ietf-tls-tls13-19#section-4.2.3.1 */
     { SSL_HND_HELLO_EXT_OID_FILTERS, "oid_filters" }, /* https://tools.ietf.org/html/draft-ietf-tls-tls13-19#section-4.3.2.1 */
     { SSL_HND_HELLO_EXT_POST_HANDSHAKE_AUTH, "post_handshake_auth" }, /* https://tools.ietf.org/html/draft-ietf-tls-tls13-20#section-4.2.5 */
+    { SSL_HND_HELLO_EXT_SIGNATURE_ALGORITHMS_CERT, "signature_algorithms_cert" }, /* https://tools.ietf.org/html/draft-ietf-tls-tls13-23 */
+    { SSL_HND_HELLO_EXT_KEY_SHARE, "key_share" }, /* https://tools.ietf.org/html/draft-ietf-tls-tls13-23 */
     { SSL_HND_HELLO_EXT_GREASE_0A0A, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
     { SSL_HND_HELLO_EXT_GREASE_1A1A, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
     { SSL_HND_HELLO_EXT_GREASE_2A2A, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
@@ -1276,6 +1278,27 @@ const value_string tls_signature_algorithm[] = {
     { 0, NULL }
 };
 
+/* https://tools.ietf.org/html/draft-ietf-tls-tls13-23#section-4.2.3 */
+const value_string tls13_signature_algorithm[] = {
+    { 0x0201, "rsa_pkcs1_sha1" },
+    { 0x0203, "ecdsa_sha1" },
+    { 0x0401, "rsa_pkcs1_sha256" },
+    { 0x0403, "ecdsa_secp256r1_sha256" },
+    { 0x0501, "rsa_pkcs1_sha384" },
+    { 0x0503, "ecdsa_secp384r1_sha384" },
+    { 0x0601, "rsa_pkcs1_sha512" },
+    { 0x0603, "ecdsa_secp521r1_sha512" },
+    { 0x0804, "rsa_pss_rsae_sha256" },
+    { 0x0805, "rsa_pss_rsae_sha384" },
+    { 0x0806, "rsa_pss_rsae_sha512" },
+    { 0x0807, "ed25519" },
+    { 0x0808, "ed448" },
+    { 0x0809, "rsa_pss_pss_sha256" },
+    { 0x080a, "rsa_pss_pss_sha384" },
+    { 0x080b, "rsa_pss_pss_sha512" },
+    { 0, NULL }
+};
+
 /* RFC 6091 3.1 */
 const value_string tls_certificate_type[] = {
     { 0, "X.509" },
@@ -1394,6 +1417,19 @@ static const ssl_alpn_protocol_t ssl_alpn_protocols[] = {
     { "h2",                 TRUE,   "http2" }, /* final version */
 };
 
+const value_string quic_transport_parameter_id[] = {
+    { SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_DATA, "initial_max_stream_data" },
+    { SSL_HND_QUIC_TP_INITIAL_MAX_DATA, "initial_max_data" },
+    { SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_ID_BIDI, "initial_max_stream_id_bidi" },
+    { SSL_HND_QUIC_TP_IDLE_TIMEOUT, "idle_timeout" },
+    { SSL_HND_QUIC_TP_OMIT_CONNECTION_ID, "omit_connection_id" },
+    { SSL_HND_QUIC_TP_MAX_PACKET_SIZE, "max_packet_size" },
+    { SSL_HND_QUIC_TP_STATELESS_RESET_TOKEN, "stateless_reset_token" },
+    { SSL_HND_QUIC_TP_ACK_DELAY_EXPONENT, "ack_delay_exponent" },
+    { SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_ID_UNI, "initial_max_stream_id_uni" },
+    { 0, NULL }
+};
+
 /* Lookup tables }}} */
 
 /* we keep this internal to packet-ssl-utils, as there should be
@@ -1742,7 +1778,7 @@ gint ssl_get_keyex_alg(gint cipher)
 
 /* StringInfo structure (len + data) functions {{{ */
 
-static gint
+gint
 ssl_data_alloc(StringInfo* str, size_t len)
 {
     str->data = (guchar *)g_malloc(len);
@@ -2052,6 +2088,7 @@ ssl_cipher_cleanup(gcry_cipher_hd_t *cipher)
         gcry_cipher_close(*cipher);
     *cipher = NULL;
 }
+/* }}} */
 
 /* Digests, Ciphers and Cipher Suites registry {{{ */
 static const SslDigestAlgo digests[]={
@@ -2707,75 +2744,72 @@ static gint tls12_handshake_hash(SslDecryptSession* ssl, gint md, StringInfo* ou
     return 0;
 }
 
-static gboolean
-tls13_hkdf_expand_label(guchar draft_version,
-                        int md, const StringInfo *secret, const char *label, const char *hash_value,
+/**
+ * Obtains the label prefix used in HKDF-Expand-Label.  This function can be
+ * inlined and removed once support for draft 19 and before is dropped.
+ */
+static inline const char *
+tls13_hkdf_label_prefix(guint8 tls13_draft_version)
+{
+    if (tls13_draft_version && tls13_draft_version < 20) {
+        return "TLS 1.3, ";
+    } else {
+        return "tls13 ";
+    }
+}
+
+/*
+ * Computes HKDF-Expand-Label(Secret, Label, "", Length) with a custom label
+ * prefix.
+ */
+gboolean
+tls13_hkdf_expand_label(int md, const StringInfo *secret,
+                        const char *label_prefix, const char *label,
                         guint16 out_len, guchar **out)
 {
-    /* draft-ietf-tls-tls13-20:
-     * HKDF-Expand-Label(Secret, Label, HashValue, Length) =
+    /* draft-ietf-tls-tls13-23:
+     * HKDF-Expand-Label(Secret, Label, Context, Length) =
      *      HKDF-Expand(Secret, HkdfLabel, Length)
      * struct {
      *     uint16 length = Length;
-     *     opaque label<7..255> = "tls13 " + Label;
-     *     opaque hash_value<0..255> = HashValue;
+     *     opaque label<7..255> = "tls13 " + Label; // "tls13 " is label prefix.
+     *     opaque context<0..255> = Context;
      * } HkdfLabel;
      *
      * RFC 5869 HMAC-based Extract-and-Expand Key Derivation Function (HKDF):
      * HKDF-Expand(PRK, info, L) -> OKM
      */
-    guchar  lastoutput[DIGEST_MAX_SIZE];
-    gcry_md_hd_t h;
     gcry_error_t err;
+    const guint label_prefix_length = (guint) strlen(label_prefix);
     const guint label_length = (guint) strlen(label);
-    const guint hash_value_length = (guint) strlen(hash_value);
-    const guint hash_len = gcry_md_get_algo_dlen(md);
 
     /* Some sanity checks */
-    DISSECTOR_ASSERT(out_len > 0 && out_len <= 255 * hash_len);
-    DISSECTOR_ASSERT(label_length > 0 && label_length <= 255 - 6);
-    DISSECTOR_ASSERT(hash_value_length <= 255);
-    DISSECTOR_ASSERT(hash_len > 0 && hash_len <= DIGEST_MAX_SIZE);
-
-    err = gcry_md_open(&h, md, GCRY_MD_FLAG_HMAC);
-    if (err) {
-        ssl_debug_printf("%s failed to invoke hash func %d: %s\n", G_STRFUNC, md, gcry_strerror(err));
-        return FALSE;
-    }
+    DISSECTOR_ASSERT(label_length > 0 && label_prefix_length + label_length <= 255);
 
-    *out = (guchar *)wmem_alloc(NULL, out_len);
-
-    for (guint offset = 0; offset < out_len; offset += hash_len) {
-        gcry_md_reset(h);
-        gcry_md_setkey(h, secret->data, secret->data_len);  /* Set PRK */
+    /* info = HkdfLabel { length, label, context } */
+    GByteArray *info = g_byte_array_new();
+    const guint16 length = g_htons(out_len);
+    g_byte_array_append(info, (const guint8 *)&length, sizeof(length));
 
-        if (offset > 0) {
-            gcry_md_write(h, lastoutput, hash_len);         /* T(1..N) */
-        }
+    const guint8 label_vector_length = label_prefix_length + label_length;
+    g_byte_array_append(info, &label_vector_length, 1);
+    g_byte_array_append(info, label_prefix, label_prefix_length);
+    g_byte_array_append(info, label, label_length);
 
-        /* info = HkdfLabel { length, label, hash_value } */
-        gcry_md_putc(h, out_len >> 8);                      /* length */
-        gcry_md_putc(h, (guint8) out_len);
-        if (draft_version && draft_version < 20) {
-            /* Draft -19 and before use a different prefix.
-             * TODO remove this once implementations are updated for D20. */
-            gcry_md_putc(h, 9 + label_length);              /* label */
-            gcry_md_write(h, "TLS 1.3, ", 9);
-        } else {
-            gcry_md_putc(h, 6 + label_length);              /* label */
-            gcry_md_write(h, "tls13 ", 6);
-        }
-        gcry_md_write(h, label, label_length);
-        gcry_md_putc(h, hash_value_length);                 /* hash_value */
-        gcry_md_write(h, hash_value, hash_value_length);
+    const guint8 context_length = 0;
+    g_byte_array_append(info, &context_length, 1);
 
-        gcry_md_putc(h, (guint8) (offset / hash_len + 1));  /* constant 0x01..N */
+    *out = (guchar *)wmem_alloc(NULL, out_len);
+    err = hkdf_expand(md, secret->data, secret->data_len, info->data, info->len, *out, out_len);
+    g_byte_array_free(info, TRUE);
 
-        memcpy(lastoutput, gcry_md_read(h, md), hash_len);
-        memcpy(*out + offset, lastoutput, MIN(hash_len, out_len - offset));
+    if (err) {
+        ssl_debug_printf("%s failed  %d: %s\n", G_STRFUNC, md, gcry_strerror(err));
+        wmem_free(NULL, *out);
+        *out = NULL;
+        return FALSE;
     }
 
-    gcry_md_close(h);
     return TRUE;
 }
 /* HMAC and the Pseudorandom function }}} */
@@ -2962,6 +2996,65 @@ ssl_decoder_destroy_cb(wmem_allocator_t *allocator _U_, wmem_cb_event_t event _U
 
     return FALSE;
 }
+
+static gboolean
+tls13_cipher_destroy_cb(wmem_allocator_t *allocator _U_, wmem_cb_event_t event _U_, void *user_data)
+{
+    tls13_cipher *cipher = (tls13_cipher *) user_data;
+
+    gcry_cipher_close(cipher->hd);
+
+    return FALSE;
+}
+
+tls13_cipher *
+tls13_cipher_create(const char *label_prefix, int cipher_algo, int cipher_mode, int hash_algo, const StringInfo *secret, const gchar **error)
+{
+    tls13_cipher       *cipher = NULL;
+    guchar             *write_key = NULL, *write_iv = NULL;
+    guint               key_length, iv_length;
+    gcry_cipher_hd_t    hd = NULL;
+    gcry_error_t        err;
+
+    /*
+     * Calculate traffic keys based on
+     * https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-7
+     */
+    key_length = (guint) gcry_cipher_get_algo_keylen(cipher_algo);
+    iv_length = TLS13_AEAD_NONCE_LENGTH;
+
+    if (!tls13_hkdf_expand_label(hash_algo, secret, label_prefix, "key", key_length, &write_key)) {
+        *error = "Key expansion (key) failed";
+        return NULL;
+    }
+    if (!tls13_hkdf_expand_label(hash_algo, secret, label_prefix, "iv", iv_length, &write_iv)) {
+        *error = "Key expansion (IV) failed";
+        goto end;
+    }
+
+    err = gcry_cipher_open(&hd, cipher_algo, cipher_mode, 0);
+    if (err) {
+        *error = wmem_strdup_printf(wmem_packet_scope(), "Decryption (initialization) failed: %s", gcry_strerror(err));
+        goto end;
+    }
+    err = gcry_cipher_setkey(hd, write_key, key_length);
+    if (err) {
+        *error = wmem_strdup_printf(wmem_packet_scope(), "Decryption (setkey) failed: %s", gcry_strerror(err));
+        gcry_cipher_close(hd);
+        goto end;
+    }
+
+    cipher = wmem_new(wmem_file_scope(), tls13_cipher);
+    wmem_register_callback(wmem_file_scope(), tls13_cipher_destroy_cb, cipher);
+    cipher->hd = hd;
+    memcpy(cipher->iv, write_iv, iv_length);
+    *error = NULL;
+
+end:
+    wmem_free(NULL, write_key);
+    wmem_free(NULL, write_iv);
+    return cipher;
+}
 /* }}} */
 
 /* (Pre-)master secrets calculations {{{ */
@@ -3437,7 +3530,7 @@ fail:
 }
 
 /* Generated the key material based on the given secret. */
-static gboolean
+gboolean
 tls13_generate_keys(SslDecryptSession *ssl_session, const StringInfo *secret, gboolean is_from_server)
 {
     gboolean    success = FALSE;
@@ -3485,11 +3578,12 @@ tls13_generate_keys(SslDecryptSession *ssl_session, const StringInfo *secret, gb
     iv_length = 12;
     ssl_debug_printf("%s key_length %u iv_length %u\n", G_STRFUNC, key_length, iv_length);
 
-    if (!tls13_hkdf_expand_label(ssl_session->session.tls13_draft_version, hash_algo, secret, "key", "", key_length, &write_key)) {
+    const char *label_prefix = tls13_hkdf_label_prefix(ssl_session->session.tls13_draft_version);
+    if (!tls13_hkdf_expand_label(hash_algo, secret, label_prefix, "key", key_length, &write_key)) {
         ssl_debug_printf("%s write_key expansion failed\n", G_STRFUNC);
         return FALSE;
     }
-    if (!tls13_hkdf_expand_label(ssl_session->session.tls13_draft_version, hash_algo, secret, "iv", "", iv_length, &write_iv)) {
+    if (!tls13_hkdf_expand_label(hash_algo, secret, label_prefix, "iv", iv_length, &write_iv)) {
         ssl_debug_printf("%s write_iv expansion failed\n", G_STRFUNC);
         goto end;
     }
@@ -4170,6 +4264,7 @@ skip_mac:
 
 #if defined(HAVE_LIBGNUTLS)
 
+/* RSA private key file processing {{{ */
 static void
 ssl_find_private_key_by_pubkey(SslDecryptSession *ssl, GHashTable *key_hash,
                                gnutls_datum_t *subjectPublicKeyInfo)
@@ -4217,7 +4312,6 @@ end:
 /* RSA private key file processing }}} */
 #endif /* ! defined(HAVE_LIBGNUTLS) */
 
-
 /*--- Start of dissector-related code below ---*/
 
 /* get ssl data for this session. if no ssl data is found allocate a new one*/
@@ -4509,20 +4603,21 @@ ssl_packet_from_server(SslSession *session, dissector_table_t table, packet_info
  * @param record_id The identifier for this record within the current packet.
  * @param flow Information about sequence numbers, etc.
  * @param type TLS Content Type (such as handshake or application_data).
+ * @param curr_layer_num_ssl The layer identifier for this TLS session.
  */
 void
-ssl_add_record_info(gint proto, packet_info *pinfo, const guchar *data, gint data_len, gint record_id, SslFlow *flow, ContentType type)
+ssl_add_record_info(gint proto, packet_info *pinfo, const guchar *data, gint data_len, gint record_id, SslFlow *flow, ContentType type, guint8 curr_layer_num_ssl)
 {
     SslRecordInfo* rec, **prec;
     SslPacketInfo* pi;
 
-    pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto, pinfo->curr_layer_num);
+    pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto, curr_layer_num_ssl);
     if (!pi)
     {
         pi = wmem_new0(wmem_file_scope(), SslPacketInfo);
         pi->srcport = pinfo->srcport;
         pi->destport = pinfo->destport;
-        p_add_proto_data(wmem_file_scope(), pinfo, proto, pinfo->curr_layer_num, pi);
+        p_add_proto_data(wmem_file_scope(), pinfo, proto, curr_layer_num_ssl, pi);
     }
 
     rec = wmem_new(wmem_file_scope(), SslRecordInfo);
@@ -4551,11 +4646,11 @@ ssl_add_record_info(gint proto, packet_info *pinfo, const guchar *data, gint dat
 
 /* search in packet data for the specified id; return a newly created tvb for the associated data */
 tvbuff_t*
-ssl_get_record_info(tvbuff_t *parent_tvb, int proto, packet_info *pinfo, gint record_id, SslRecordInfo **matched_record)
+ssl_get_record_info(tvbuff_t *parent_tvb, int proto, packet_info *pinfo, gint record_id, guint8 curr_layer_num_ssl, SslRecordInfo **matched_record)
 {
     SslRecordInfo* rec;
     SslPacketInfo* pi;
-    pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto, pinfo->curr_layer_num);
+    pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto, curr_layer_num_ssl);
 
     if (!pi)
         return NULL;
@@ -4640,23 +4735,26 @@ ssl_parse_key_list(const ssldecrypt_assoc_t *uats, GHashTable *key_hash, const c
 
     if ((gint)strlen(uats->password) == 0) {
         priv_key = rsa_load_pem_key(fp, &err);
-        if (err) {
-            ssl_debug_printf("%s\n", err);
-            g_free(err);
-        }
     } else {
         priv_key = rsa_load_pkcs12(fp, uats->password, &err);
-        if (err) {
-            report_failure("%s\n", err);
-            g_free(err);
-        }
     }
     fclose(fp);
 
     if (!priv_key) {
-        report_failure("Can't load private key from %s\n", uats->keyfile);
+        if (err) {
+            report_failure("Can't load private key from %s: %s",
+                           uats->keyfile, err);
+            g_free(err);
+        } else
+            report_failure("Can't load private key from %s: unknown error",
+                           uats->keyfile);
         return;
     }
+    if (err) {
+        report_failure("Load of private key from %s \"succeeded\" with error %s",
+                       uats->keyfile, err);
+        g_free(err);
+    }
 
     key_id = (guchar *) g_malloc0(key_id_len);
     ret = gnutls_x509_privkey_get_key_id(priv_key, 0, key_id, &key_id_len);
@@ -4842,23 +4940,23 @@ ssl_finalize_decryption(SslDecryptSession *ssl, ssl_master_key_map_t *mk_map)
     }
 } /* }}} */
 
-/* Load the new key. */
-void
-tls13_change_key(SslDecryptSession *ssl, ssl_master_key_map_t *mk_map,
-                 gboolean is_from_server, TLSRecordType type)
+/* Load the traffic key secret from the keylog file. */
+StringInfo *
+tls13_load_secret(SslDecryptSession *ssl, ssl_master_key_map_t *mk_map,
+                  gboolean is_from_server, TLSRecordType type)
 {
     GHashTable *key_map;
     const char *label;
 
     if (ssl->session.version != TLSV1DOT3_VERSION) {
         ssl_debug_printf("%s TLS version %#x is not 1.3\n", G_STRFUNC, ssl->session.version);
-        return;
+        return NULL;
     }
 
     if (ssl->client_random.data_len == 0) {
         /* May happen if Hello message is missing and Finished is found. */
         ssl_debug_printf("%s missing Client Random\n", G_STRFUNC);
-        return;
+        return NULL;
     }
 
     switch (type) {
@@ -4902,13 +5000,26 @@ tls13_change_key(SslDecryptSession *ssl, ssl_master_key_map_t *mk_map,
         } else {
             ssl->client = NULL;
         }
-        return;
+        return NULL;
     }
 
     /* TLS 1.3 secret found, set new keys. */
     ssl_debug_printf("%s Retrieved TLS 1.3 traffic secret.\n", G_STRFUNC);
     ssl_print_string("Client Random", &ssl->client_random);
     ssl_print_string(label, secret);
+    return secret;
+}
+
+/* Load the new key. */
+void
+tls13_change_key(SslDecryptSession *ssl, ssl_master_key_map_t *mk_map,
+                 gboolean is_from_server, TLSRecordType type)
+{
+    StringInfo *secret = tls13_load_secret(ssl, mk_map, is_from_server, type);
+    if (!secret) {
+        return;
+    }
+
     if (tls13_generate_keys(ssl, secret, is_from_server)) {
         /*
          * Remember the application traffic secret to support Key Update. The
@@ -4960,8 +5071,9 @@ tls13_key_update(SslDecryptSession *ssl, gboolean is_from_server)
     int hash_algo = ssl_get_digest_by_name(hash_name);
     const guint hash_len = app_secret->data_len;
     guchar *new_secret;
-    if (!tls13_hkdf_expand_label(ssl->session.tls13_draft_version,
-                                 hash_algo, app_secret, "application traffic secret", "",
+    if (!tls13_hkdf_expand_label(hash_algo, app_secret,
+                                 tls13_hkdf_label_prefix(ssl->session.tls13_draft_version),
+                                 "application traffic secret",
                                  hash_len, &new_secret)) {
         ssl_debug_printf("%s traffic_secret_N+1 expansion failed\n", G_STRFUNC);
         return;
@@ -5292,13 +5404,9 @@ ssl_print_string(const gchar* name, const StringInfo* data)
 /* checks for SSL and DTLS UAT key list fields */
 
 gboolean
-ssldecrypt_uat_fld_ip_chk_cb(void* r _U_, const char* p, guint len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
+ssldecrypt_uat_fld_ip_chk_cb(void* r _U_, const char* p _U_, guint len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
 {
-    if (!p || strlen(p) == 0u) {
-        *err = g_strdup("No IP address given.");
-        return FALSE;
-    }
-
+    // This should be removed in favor of Decode As. Make it optional.
     *err = NULL;
     return TRUE;
 }
@@ -5307,8 +5415,9 @@ gboolean
 ssldecrypt_uat_fld_port_chk_cb(void* r _U_, const char* p, guint len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
 {
     if (!p || strlen(p) == 0u) {
-        *err = g_strdup("No Port given.");
-        return FALSE;
+        // This should be removed in favor of Decode As. Make it optional.
+        *err = NULL;
+        return TRUE;
     }
 
     if (strcmp(p, "start_tls") != 0){
@@ -5526,6 +5635,16 @@ ssl_dissect_change_cipher_spec(ssl_common_dissect_t *hf, tvbuff_t *tvb,
             val_to_str_const(SSL_ID_CHG_CIPHER_SPEC, ssl_31_content_type, "unknown"));
     ti = proto_tree_add_item(tree, hf->hf.change_cipher_spec, tvb, offset, 1, ENC_NA);
 
+    if (session->version == TLSV1DOT3_VERSION) {
+        /* CCS is a dummy message in TLS 1.3, do not parse it further. */
+        return;
+    }
+
+    /* Remember frame number of first CCS */
+    guint32 *ccs_frame = is_from_server ? &session->server_ccs_frame : &session->client_ccs_frame;
+    if (*ccs_frame == 0)
+        *ccs_frame = pinfo->num;
+
     /* Use heuristics to detect an abbreviated handshake, assume that missing
      * ServerHelloDone implies reusing previously negotiating keys. Then when
      * a Session ID or ticket is present, it must be a resumed session.
@@ -5554,6 +5673,35 @@ ssl_dissect_change_cipher_spec(ssl_common_dissect_t *hf, tvbuff_t *tvb,
 }
 
 /** Begin of handshake(22) record dissections */
+
+/* Dissects a SignatureScheme (TLS 1.3) or SignatureAndHashAlgorithm (TLS 1.2).
+ * {{{ */
+static void
+tls_dissect_signature_algorithm(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *tree, guint32 offset)
+{
+    guint32     sighash, hashalg, sigalg;
+    proto_item *ti_sigalg;
+    proto_tree *sigalg_tree;
+
+    ti_sigalg = proto_tree_add_item_ret_uint(tree, hf->hf.hs_sig_hash_alg, tvb,
+                                             offset, 2, ENC_BIG_ENDIAN, &sighash);
+    sigalg_tree = proto_item_add_subtree(ti_sigalg, hf->ett.hs_sig_hash_alg);
+
+    /* TLS 1.2: SignatureAndHashAlgorithm { hash, signature } */
+    proto_tree_add_item_ret_uint(sigalg_tree, hf->hf.hs_sig_hash_hash, tvb,
+                                 offset, 1, ENC_BIG_ENDIAN, &hashalg);
+    proto_tree_add_item_ret_uint(sigalg_tree, hf->hf.hs_sig_hash_sig, tvb,
+                                 offset + 1, 1, ENC_BIG_ENDIAN, &sigalg);
+
+    /* No TLS 1.3 SignatureScheme? Fallback to TLS 1.2 interpretation. */
+    if (!try_val_to_str(sighash, tls13_signature_algorithm)) {
+        proto_item_set_text(ti_sigalg, "Signature Algorithm: %s %s (0x%04x)",
+                val_to_str_const(hashalg, tls_hash_algorithm, "Unknown"),
+                val_to_str_const(sigalg, tls_signature_algorithm, "Unknown"),
+                sighash);
+    }
+} /* }}} */
+
 /* dissect a list of hash algorithms, return the number of bytes dissected
    this is used for the signature algorithms extension and for the
    TLS1.2 certificate request. {{{ */
@@ -5568,7 +5716,7 @@ ssl_dissect_hash_alg_list(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *t
      *  } SignatureAndHashAlgorithm;
      *  SignatureAndHashAlgorithm supported_signature_algorithms<2..2^16-2>;
      */
-    proto_tree *subtree, *alg_tree;
+    proto_tree *subtree;
     proto_item *ti;
     guint sh_alg_length;
     guint32     next_offset;
@@ -5587,15 +5735,7 @@ ssl_dissect_hash_alg_list(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *t
     subtree = proto_item_add_subtree(ti, hf->ett.hs_sig_hash_algs);
 
     while (offset + 2 <= next_offset) {
-        ti = proto_tree_add_item(subtree, hf->hf.hs_sig_hash_alg,
-                                 tvb, offset, 2, ENC_BIG_ENDIAN);
-        alg_tree = proto_item_add_subtree(ti, hf->ett.hs_sig_hash_alg);
-
-        proto_tree_add_item(alg_tree, hf->hf.hs_sig_hash_hash,
-                            tvb, offset, 1, ENC_BIG_ENDIAN);
-        proto_tree_add_item(alg_tree, hf->hf.hs_sig_hash_sig,
-                            tvb, offset+1, 1, ENC_BIG_ENDIAN);
-
+        tls_dissect_signature_algorithm(hf, tvb, subtree, offset);
         offset += 2;
     }
 
@@ -6037,7 +6177,7 @@ ssl_dissect_hnd_hello_ext_supported_versions(ssl_common_dissect_t *hf, tvbuff_t
     next_offset = offset + versions_length;
 
     while (offset + 2 <= next_offset) {
-        proto_tree_add_item(tree, hf->hf.hs_ext_supported_versions, tvb, offset, 2, ENC_BIG_ENDIAN);
+        proto_tree_add_item(tree, hf->hf.hs_ext_supported_version, tvb, offset, 2, ENC_BIG_ENDIAN);
         offset += 2;
     }
     if (!ssl_end_vector(hf, tvb, pinfo, tree, offset, next_offset)) {
@@ -6314,16 +6454,181 @@ ssl_dissect_hnd_hello_ext_cert_type(ssl_common_dissect_t *hf, tvbuff_t *tvb,
     return offset;
 }
 
+static guint32
+ssl_dissect_hnd_hello_ext_quic_transport_parameters(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *pinfo,
+                                                    proto_tree *tree, guint32 offset, guint32 offset_end,
+                                                    guint8 hnd_type, SslDecryptSession *ssl _U_)
+{
+    guint32 quic_length, parameter_length, supported_versions_length, next_offset;
+
+    /* https://tools.ietf.org/html/draft-ietf-quic-transport-08#section-7.4
+     *  uint32 QuicVersion;
+     *  enum {
+     *     initial_max_stream_data(0),
+     *     initial_max_data(1),
+     *     initial_max_stream_id_bidi(2),
+     *     idle_timeout(3),
+     *     truncate_connection_id(4),
+     *     max_packet_size(5),
+     *     stateless_reset_token(6),
+     *     ack_delay_exponent(7),
+     *     initial_max_stream_id_uni(8),
+     *     (65535)
+     *  } TransportParameterId;
+     *
+     *   struct {
+     *     TransportParameterId parameter;
+     *     opaque value<0..2^16-1>;
+     *  } TransportParameter;
+     *
+     *  struct {
+     *      select (Handshake.msg_type) {
+     *          case client_hello:
+     *              QuicVersion initial_version;
+     *
+     *         case encrypted_extensions:
+     *              QuicVersion negotiated_version;
+     *              QuicVersion supported_versions<4..2^8-4>;
+     *      };
+     *      TransportParameter parameters<22..2^16-1>;
+     *  } TransportParameters;
+     */
+    switch (hnd_type) {
+    case SSL_HND_CLIENT_HELLO:
+        proto_tree_add_item(tree, hf->hf.hs_ext_quictp_initial_version,
+                            tvb, offset, 4, ENC_BIG_ENDIAN);
+        offset += 4;
+        break;
+    case SSL_HND_ENCRYPTED_EXTENSIONS:
+        proto_tree_add_item(tree, hf->hf.hs_ext_quictp_negotiated_version,
+                            tvb, offset, 4, ENC_BIG_ENDIAN);
+        offset += 4;
+        /* QuicVersion supported_versions<4..2^8-4>;*/
+        if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &supported_versions_length,
+                            hf->hf.hs_ext_quictp_supported_versions_len, 4, G_MAXUINT8-3)) {
+            return offset_end;
+        }
+        offset += 1;
+        next_offset = offset + supported_versions_length;
+
+        while (offset < next_offset) {
+            proto_tree_add_item(tree, hf->hf.hs_ext_quictp_supported_versions,
+                                tvb, offset, 4, ENC_BIG_ENDIAN);
+            offset += 4;
+        }
+        break;
+    case SSL_HND_NEWSESSION_TICKET:
+        break;
+    default:
+        return offset;
+    }
+
+    /* TransportParameter parameters<22..2^16-1>; */
+    if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &quic_length,
+                        hf->hf.hs_ext_quictp_len, 22, G_MAXUINT16)) {
+        return offset_end;
+    }
+    offset += 2;
+    next_offset = offset + quic_length;
+
+    while (offset < next_offset) {
+        guint32 parameter_type;
+        proto_tree *parameter_tree;
+
+        parameter_tree = proto_tree_add_subtree(tree, tvb, offset, 4, hf->ett.hs_ext_quictp_parameter,
+                                                NULL, "Parameter");
+        /* TransportParameterId parameter */
+        proto_tree_add_item_ret_uint(parameter_tree, hf->hf.hs_ext_quictp_parameter_type,
+                                     tvb, offset, 2, ENC_BIG_ENDIAN, &parameter_type);
+        offset += 2;
+        proto_item_append_text(parameter_tree, ": %s", val_to_str(parameter_type, quic_transport_parameter_id, "Unknown"));
+
+        /* opaque value<0..2^16-1> */
+        if (!ssl_add_vector(hf, tvb, pinfo, parameter_tree, offset, next_offset, &parameter_length,
+                            hf->hf.hs_ext_quictp_parameter_len, 0, G_MAXUINT16)) {
+            return next_offset;
+        }
+        offset += 2;
+        proto_item_append_text(parameter_tree, " (len=%u)", parameter_length);
+        proto_item_set_len(parameter_tree, 4 + parameter_length);
+
+        proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_value,
+                            tvb, offset, parameter_length, ENC_NA);
+
+        switch (parameter_type) {
+            case SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_DATA:
+                proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_initial_max_stream_data,
+                                    tvb, offset, 4, ENC_BIG_ENDIAN);
+                proto_item_append_text(parameter_tree, " %u", tvb_get_ntohl(tvb, offset));
+                offset += 4;
+            break;
+            case SSL_HND_QUIC_TP_INITIAL_MAX_DATA:
+                proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_initial_max_data,
+                                    tvb, offset, 4, ENC_BIG_ENDIAN);
+                proto_item_append_text(parameter_tree, " %u", tvb_get_ntohl(tvb, offset));
+                offset += 4;
+            break;
+            case SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_ID_BIDI:
+                proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_initial_max_stream_id_bidi,
+                                    tvb, offset, 4, ENC_BIG_ENDIAN);
+                proto_item_append_text(parameter_tree, " %u", tvb_get_ntohl(tvb, offset));
+                offset += 4;
+            break;
+            case SSL_HND_QUIC_TP_IDLE_TIMEOUT:
+                proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_idle_timeout,
+                                    tvb, offset, 2, ENC_BIG_ENDIAN);
+                proto_item_append_text(parameter_tree, " %u secs", tvb_get_ntohs(tvb, offset));
+                offset += 2;
+            break;
+            case SSL_HND_QUIC_TP_OMIT_CONNECTION_ID:
+                /* No Payload */
+            break;
+            case SSL_HND_QUIC_TP_MAX_PACKET_SIZE:
+                proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_max_packet_size,
+                                    tvb, offset, 2, ENC_BIG_ENDIAN);
+                proto_item_append_text(parameter_tree, " %u", tvb_get_ntohs(tvb, offset));
+                /*TODO display expert info about invalid value (< 1252 or >65527) ? */
+                offset += 2;
+            break;
+            case SSL_HND_QUIC_TP_STATELESS_RESET_TOKEN:
+                proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_stateless_reset_token,
+                                    tvb, offset, 16, ENC_BIG_ENDIAN);
+                offset += 16;
+            break;
+            case SSL_HND_QUIC_TP_ACK_DELAY_EXPONENT:
+                proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_ack_delay_exponent,
+                                    tvb, offset, 1, ENC_BIG_ENDIAN);
+                /*TODO display multiplier (x8) and expert info about invaluid value (> 20) ? */
+                offset += 1;
+            break;
+            case SSL_HND_QUIC_TP_INITIAL_MAX_STREAM_ID_UNI:
+                proto_tree_add_item(parameter_tree, hf->hf.hs_ext_quictp_parameter_initial_max_stream_id_uni,
+                                    tvb, offset, 4, ENC_BIG_ENDIAN);
+                proto_item_append_text(parameter_tree, " %u", tvb_get_ntohl(tvb, offset));
+                offset += 4;
+            break;
+            default:
+                offset += parameter_length;
+                /*TODO display expert info about unknown ? */
+            break;
+        }
+
+    }
+
+    return offset;
+}
+
 static gint
 ssl_dissect_hnd_hello_common(ssl_common_dissect_t *hf, tvbuff_t *tvb,
                              proto_tree *tree, guint32 offset,
                              SslSession *session, SslDecryptSession *ssl,
-                             gboolean from_server)
+                             gboolean from_server, gboolean is_hrr)
 {
     nstime_t     gmt_unix_time;
     guint8       sessid_length;
     proto_tree  *rnd_tree;
     proto_tree  *ti_rnd;
+    guint8       draft_version = session->tls13_draft_version;
 
     /* Prepare for renegotiation by resetting the state. */
     ssl_reset_session(session, ssl, !from_server);
@@ -6363,10 +6668,15 @@ ssl_dissect_hnd_hello_common(ssl_common_dissect_t *hf, tvbuff_t *tvb,
                 tvb, offset, 28, ENC_NA);
         offset += 28;
     } else {
+        if (is_hrr) {
+            proto_item_append_text(ti_rnd, " (HelloRetryRequest magic)");
+        }
+
         offset += 32;
     }
 
-    if (from_server == 0 || session->version != TLSV1DOT3_VERSION) { /* No Session ID with TLS 1.3 on Server Hello */
+    /* No Session ID with TLS 1.3 on Server Hello before draft -22 */
+    if (from_server == 0 || !(session->version == TLSV1DOT3_VERSION && draft_version > 0 && draft_version < 22)) {
         /* show the session id (length followed by actual Session ID) */
         sessid_length = tvb_get_guint8(tvb, offset);
         proto_tree_add_item(tree, hf->hf.hs_session_id_len,
@@ -6393,9 +6703,31 @@ ssl_dissect_hnd_hello_common(ssl_common_dissect_t *hf, tvbuff_t *tvb,
 }
 
 static gint
-ssl_dissect_hnd_hello_ext_status_request(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *tree,
-                                         guint32 offset, gboolean has_length)
+ssl_dissect_hnd_hello_ext_status_request(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *pinfo,
+                                         proto_tree *tree, guint32 offset, guint32 offset_end,
+                                         gboolean has_length)
 {
+    /* TLS 1.2/1.3 status_request Client Hello Extension.
+     * TLS 1.2 status_request_v2 CertificateStatusRequestItemV2 type.
+     * https://tools.ietf.org/html/rfc6066#section-8 (status_request)
+     * https://tools.ietf.org/html/rfc6961#section-2.2 (status_request_v2)
+     *  struct {
+     *      CertificateStatusType status_type;
+     *      uint16 request_length;  // for status_request_v2
+     *      select (status_type) {
+     *          case ocsp: OCSPStatusRequest;
+     *          case ocsp_multi: OCSPStatusRequest;
+     *      } request;
+     *  } CertificateStatusRequest; // CertificateStatusRequestItemV2
+     *
+     *  enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
+     *  struct {
+     *      ResponderID responder_id_list<0..2^16-1>;
+     *      Extensions  request_extensions;
+     *  } OCSPStatusRequest;
+     *  opaque ResponderID<1..2^16-1>;
+     *  opaque Extensions<0..2^16-1>;
+     */
     guint    cert_status_type;
 
     cert_status_type = tvb_get_guint8(tvb, offset);
@@ -6413,37 +6745,36 @@ ssl_dissect_hnd_hello_ext_status_request(ssl_common_dissect_t *hf, tvbuff_t *tvb
     case SSL_HND_CERT_STATUS_TYPE_OCSP:
     case SSL_HND_CERT_STATUS_TYPE_OCSP_MULTI:
         {
-            guint16      responder_id_list_len;
-            guint16      request_extensions_len;
-            proto_item  *responder_id;
-            proto_item  *request_extensions;
-
-            responder_id_list_len = tvb_get_ntohs(tvb, offset);
-            responder_id =
-                proto_tree_add_item(tree,
-                                    hf->hf.hs_ext_cert_status_responder_id_list_len,
-                                    tvb, offset, 2, ENC_BIG_ENDIAN);
+            guint32      responder_id_list_len;
+            guint32      request_extensions_len;
+
+            /* ResponderID responder_id_list<0..2^16-1> */
+            if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &responder_id_list_len,
+                                hf->hf.hs_ext_cert_status_responder_id_list_len, 0, G_MAXUINT16)) {
+                return offset_end;
+            }
             offset += 2;
             if (responder_id_list_len != 0) {
-                expert_add_info_format(NULL, responder_id,
-                                       &hf->ei.hs_ext_cert_status_undecoded,
+                proto_tree_add_expert_format(tree, pinfo, &hf->ei.hs_ext_cert_status_undecoded,
+                                             tvb, offset, responder_id_list_len,
                                        "Responder ID list is not implemented, contact Wireshark"
                                        " developers if you want this to be supported");
-                /* Non-empty responder ID list would mess with extensions. */
-                break;
             }
+            offset += responder_id_list_len;
 
-            request_extensions_len = tvb_get_ntohs(tvb, offset);
-            request_extensions =
-                proto_tree_add_item(tree,
-                                    hf->hf.hs_ext_cert_status_request_extensions_len, tvb, offset,
-                                    2, ENC_BIG_ENDIAN);
+            /* opaque Extensions<0..2^16-1> */
+            if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &request_extensions_len,
+                                hf->hf.hs_ext_cert_status_request_extensions_len, 0, G_MAXUINT16)) {
+                return offset_end;
+            }
             offset += 2;
-            if (request_extensions_len != 0)
-                expert_add_info_format(NULL, request_extensions,
-                                       &hf->ei.hs_ext_cert_status_undecoded,
+            if (request_extensions_len != 0) {
+                proto_tree_add_expert_format(tree, pinfo, &hf->ei.hs_ext_cert_status_undecoded,
+                                             tvb, offset, request_extensions_len,
                                        "Request Extensions are not implemented, contact"
                                        " Wireshark developers if you want this to be supported");
+            }
+            offset += request_extensions_len;
             break;
         }
     }
@@ -6451,19 +6782,101 @@ ssl_dissect_hnd_hello_ext_status_request(ssl_common_dissect_t *hf, tvbuff_t *tvb
     return offset;
 }
 
-static gint
-ssl_dissect_hnd_hello_ext_status_request_v2(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *tree,
-                                            guint32 offset)
+static guint
+ssl_dissect_hnd_hello_ext_status_request_v2(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *pinfo,
+                                            proto_tree *tree, guint32 offset, guint32 offset_end)
 {
-    gint32   list_len;
+    /* https://tools.ietf.org/html/rfc6961#section-2.2
+     *  struct {
+     *    CertificateStatusRequestItemV2 certificate_status_req_list<1..2^16-1>;
+     *  } CertificateStatusRequestListV2;
+     */
+    guint32 req_list_length, next_offset;
 
-    list_len = tvb_get_ntohs(tvb, offset);
+    /* CertificateStatusRequestItemV2 certificate_status_req_list<1..2^16-1> */
+    if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &req_list_length,
+                        hf->hf.hs_ext_cert_status_request_list_len, 1, G_MAXUINT16)) {
+        return offset_end;
+    }
     offset += 2;
+    next_offset = offset + req_list_length;
+
+    while (offset < next_offset) {
+        offset = ssl_dissect_hnd_hello_ext_status_request(hf, tvb, pinfo, tree, offset, next_offset, TRUE);
+    }
+
+    return offset;
+}
+
+static guint32
+tls_dissect_ocsp_response(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+                          guint32 offset, guint32 offset_end)
+{
+    guint32     response_length;
+    proto_item *ocsp_resp;
+    proto_tree *ocsp_resp_tree;
+    asn1_ctx_t  asn1_ctx;
+
+    /* opaque OCSPResponse<1..2^24-1>; */
+    if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &response_length,
+                        hf->hf.hs_ocsp_response_len, 1, G_MAXUINT24)) {
+        return offset_end;
+    }
+    offset += 3;
+
+    ocsp_resp = proto_tree_add_item(tree, proto_ocsp, tvb, offset,
+                                    response_length, ENC_BIG_ENDIAN);
+    proto_item_set_text(ocsp_resp, "OCSP Response");
+    ocsp_resp_tree = proto_item_add_subtree(ocsp_resp, hf->ett.ocsp_response);
+    asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
+    dissect_ocsp_OCSPResponse(FALSE, tvb, offset, &asn1_ctx, ocsp_resp_tree, -1);
+    offset += response_length;;
+
+    return offset;
+}
+
+guint32
+tls_dissect_hnd_certificate_status(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *pinfo,
+                                   proto_tree *tree, guint32 offset, guint32 offset_end)
+{
+    /* TLS 1.2 "CertificateStatus" handshake message.
+     * TLS 1.3 "status_request" Certificate extension.
+     *  struct {
+     *    CertificateStatusType status_type;
+     *    select (status_type) {
+     *      case ocsp: OCSPResponse;
+     *      case ocsp_multi: OCSPResponseList;  // status_request_v2
+     *    } response;
+     *  } CertificateStatus;
+     *  opaque OCSPResponse<1..2^24-1>;
+     *  struct {
+     *    OCSPResponse ocsp_response_list<1..2^24-1>;
+     *  } OCSPResponseList;                     // status_request_v2
+     */
+    guint32     status_type, resp_list_length, next_offset;
+
+    proto_tree_add_item_ret_uint(tree, hf->hf.hs_ext_cert_status_type,
+                                 tvb, offset, 1, ENC_BIG_ENDIAN, &status_type);
+    offset += 1;
+
+    switch (status_type) {
+    case SSL_HND_CERT_STATUS_TYPE_OCSP:
+        offset = tls_dissect_ocsp_response(hf, tvb, pinfo, tree, offset, offset_end);
+        break;
+
+    case SSL_HND_CERT_STATUS_TYPE_OCSP_MULTI:
+        /* OCSPResponse ocsp_response_list<1..2^24-1> */
+        if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &resp_list_length,
+                            hf->hf.hs_ocsp_response_list_len, 1, G_MAXUINT24)) {
+            return offset_end;
+        }
+        offset += 3;
+        next_offset = offset + resp_list_length;
 
-    while (list_len > 0) {
-        guint32 prev_offset = offset;
-        offset = ssl_dissect_hnd_hello_ext_status_request(hf, tvb, tree, offset, TRUE);
-        list_len -= (offset - prev_offset);
+        while (offset < next_offset) {
+            offset = tls_dissect_ocsp_response(hf, tvb, pinfo, tree, offset, next_offset);
+        }
+        break;
     }
 
     return offset;
@@ -6567,13 +6980,18 @@ tls_dissect_sct(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *pinfo, pro
      *      digitally-signed struct { ... };
      *  } SignedCertificateTimestamp;
      */
+    guint32     sct_version;
     guint64     sct_timestamp_ms;
     nstime_t    sct_timestamp;
     guint32     exts_len;
     const gchar *log_name;
 
-    proto_tree_add_item(tree, hf->hf.sct_sct_version, tvb, offset, 1, ENC_NA);
+    proto_tree_add_item_ret_uint(tree, hf->hf.sct_sct_version, tvb, offset, 1, ENC_NA, &sct_version);
     offset++;
+    if (sct_version != 0) {
+        // TODO expert info about unknown SCT version?
+        return offset;
+    }
     proto_tree_add_item(tree, hf->hf.sct_sct_logid, tvb, offset, 32, ENC_BIG_ENDIAN);
     log_name = bytesval_to_str(tvb_get_ptr(tvb, offset, 32), 32, ct_logids, "Unknown Log");
     proto_item_append_text(tree, " (%s)", log_name);
@@ -6700,15 +7118,76 @@ ssl_is_authoritative_version_message(guint8 content_type, guint8 handshake_type,
             ssl_is_valid_content_type(content_type));
 }
 
+/**
+ * Scan a Server Hello handshake message for the negotiated version. For TLS 1.3
+ * draft 22 and newer, it also checks whether it is a HelloRetryRequest.
+ */
+void
+tls_scan_server_hello(tvbuff_t *tvb, guint32 offset, guint32 offset_end,
+                      guint16 *server_version, gboolean *is_hrr)
+{
+    /* SHA256("HelloRetryRequest") */
+    static const guint8 tls13_hrr_random_magic[] = {
+        0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91,
+        0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c
+    };
+    guint8  session_id_length;
+
+    *server_version = tvb_get_ntohs(tvb, offset);
+
+    /*
+     * Try to look for supported_versions extension. Minimum length:
+     * 2 + 32 + 1 = 35 (version, random, session id length)
+     * 2 + 1 + 2 = 5 (cipher suite, compression method, extensions length)
+     * 2 + 2 + 2 = 6 (ext type, ext len, version)
+     */
+    if (*server_version == TLSV1DOT2_VERSION && offset_end - offset >= 46) {
+        offset += 2;
+        *is_hrr = tvb_memeql(tvb, offset, tls13_hrr_random_magic, sizeof(tls13_hrr_random_magic)) == 0;
+        offset += 32;
+        session_id_length = tvb_get_guint8(tvb, offset);
+        offset++;
+        if (offset_end - offset < session_id_length + 5u) {
+            return;
+        }
+        offset += session_id_length + 5;
+
+        while (offset_end - offset >= 6) {
+            guint16 ext_type = tvb_get_ntohs(tvb, offset);
+            guint16 ext_len = tvb_get_ntohs(tvb, offset + 2);
+            if (offset_end - offset < 4u + ext_len) {
+                break;  /* not enough data for type, length and data */
+            }
+            if (ext_type == SSL_HND_HELLO_EXT_SUPPORTED_VERSIONS && ext_len == 2) {
+                *server_version = tvb_get_ntohs(tvb, offset + 4);
+                return;
+            }
+            offset += 4 + ext_len;
+        }
+    } else {
+        *is_hrr = FALSE;
+    }
+}
+
 void
 ssl_try_set_version(SslSession *session, SslDecryptSession *ssl,
                     guint8 content_type, guint8 handshake_type,
                     gboolean is_dtls, guint16 version)
 {
+    guint8 tls13_draft = 0;
+
     if (!ssl_is_authoritative_version_message(content_type, handshake_type,
                 is_dtls))
         return;
 
+    if (handshake_type == SSL_HND_SERVER_HELLO) {
+        tls13_draft = tls13_draft_version(version);
+        if (tls13_draft != 0) {
+            /* This is TLS 1.3 (a draft version). */
+            version = TLSV1DOT3_VERSION;
+        }
+    }
+
     switch (version) {
     case SSLV3_VERSION:
     case TLSV1_VERSION:
@@ -6730,6 +7209,7 @@ ssl_try_set_version(SslSession *session, SslDecryptSession *ssl,
         return;
     }
 
+    session->tls13_draft_version = tls13_draft;
     session->version = version;
     if (ssl) {
         ssl->state |= SSL_VERSION;
@@ -6815,7 +7295,7 @@ ssl_dissect_hnd_cli_hello(ssl_common_dissect_t *hf, tvbuff_t *tvb,
     offset += 2;
 
     /* dissect fields that are also present in ClientHello */
-    offset = ssl_dissect_hnd_hello_common(hf, tvb, tree, offset, session, ssl, FALSE);
+    offset = ssl_dissect_hnd_hello_common(hf, tvb, tree, offset, session, ssl, FALSE, FALSE);
 
     /* fields specific for DTLS (cookie_len, cookie) */
     if (dtls_hfs != NULL) {
@@ -6906,7 +7386,7 @@ void
 ssl_dissect_hnd_srv_hello(ssl_common_dissect_t *hf, tvbuff_t *tvb,
                           packet_info* pinfo, proto_tree *tree, guint32 offset, guint32 offset_end,
                           SslSession *session, SslDecryptSession *ssl,
-                          gboolean is_dtls)
+                          gboolean is_dtls, gboolean is_hrr)
 {
     /* struct {
      *     ProtocolVersion server_version;
@@ -6917,20 +7397,10 @@ ssl_dissect_hnd_srv_hello(ssl_common_dissect_t *hf, tvbuff_t *tvb,
      *     Extension server_hello_extension_list<0..2^16-1>;
      * } ServerHello;
      */
-    guint16 server_version;
+    guint8  draft_version = session->tls13_draft_version;
 
-    /* This version is always better than the guess at the Record Layer */
-    server_version = tvb_get_ntohs(tvb, offset);
-    if((server_version & 0xFF00) == 0x7f00) { /* if server_version start with 0x7f, it is (and force) TLS 1.3 */
-        session->tls13_draft_version = server_version & 0xff;
-        server_version = TLSV1DOT3_VERSION;
-    } else {
-        session->tls13_draft_version = 0;
-    }
-    ssl_try_set_version(session, ssl, SSL_ID_HANDSHAKE, SSL_HND_SERVER_HELLO,
-            is_dtls, server_version);
     col_set_str(pinfo->cinfo, COL_PROTOCOL,
-                val_to_str_const(server_version, ssl_version_short_names, "SSL"));
+                val_to_str_const(session->version, ssl_version_short_names, "SSL"));
 
     /* Initially assume that the session is resumed. If this is not the case, a
      * ServerHelloDone will be observed before the ChangeCipherSpec message
@@ -6943,7 +7413,7 @@ ssl_dissect_hnd_srv_hello(ssl_common_dissect_t *hf, tvbuff_t *tvb,
     offset += 2;
 
     /* dissect fields that are also present in ClientHello */
-    offset = ssl_dissect_hnd_hello_common(hf, tvb, tree, offset, session, ssl, TRUE);
+    offset = ssl_dissect_hnd_hello_common(hf, tvb, tree, offset, session, ssl, TRUE, is_hrr);
 
     if (ssl) {
         /* store selected cipher suite for decryption */
@@ -6955,7 +7425,8 @@ ssl_dissect_hnd_srv_hello(ssl_common_dissect_t *hf, tvbuff_t *tvb,
                         tvb, offset, 2, ENC_BIG_ENDIAN);
     offset += 2;
 
-    if (session->version != TLSV1DOT3_VERSION) { /* No compression with TLS 1.3 */
+    /* No compression with TLS 1.3 before draft -22 */
+    if (!(session->version == TLSV1DOT3_VERSION && draft_version > 0 && draft_version < 22)) {
         if (ssl) {
             /* store selected compression method for decryption */
             ssl->session.compression = tvb_get_guint8(tvb, offset);
@@ -6969,7 +7440,8 @@ ssl_dissect_hnd_srv_hello(ssl_common_dissect_t *hf, tvbuff_t *tvb,
     /* SSL v3.0 has no extensions, so length field can indeed be missing. */
     if (offset < offset_end) {
         ssl_dissect_hnd_extension(hf, tvb, tree, pinfo, offset,
-                                  offset_end, SSL_HND_SERVER_HELLO,
+                                  offset_end,
+                                  is_hrr ? SSL_HND_HELLO_RETRY_REQUEST : SSL_HND_SERVER_HELLO,
                                   session, ssl, is_dtls);
     }
 }
@@ -6992,25 +7464,32 @@ ssl_dissect_hnd_new_ses_ticket(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_i
      *  struct {
      *      uint32 ticket_lifetime;
      *      uint32 ticket_age_add;
-     *      opaque ticket_nonce<1..255>; #add in TLS 1.3 draft 21 (Section 4.6.1)
+     *      opaque ticket_nonce<0..255>;    // new in draft -21, updated in -22
      *      opaque ticket<1..2^16-1>;
      *      Extension extensions<0..2^16-2>;
      *  } NewSessionTicket;
      */
     proto_tree *subtree;
+    proto_item *subitem;
     guint32     ticket_len;
     gboolean    is_tls13 = session->version == TLSV1DOT3_VERSION;
     guchar      draft_version = session->tls13_draft_version;
+    guint32     lifetime_hint;
 
     subtree = proto_tree_add_subtree(tree, tvb, offset, offset_end - offset,
                                      hf->ett.session_ticket, NULL,
                                      "TLS Session Ticket");
 
     /* ticket lifetime hint */
-    proto_tree_add_item(subtree, hf->hf.hs_session_ticket_lifetime_hint,
-                        tvb, offset, 4, ENC_BIG_ENDIAN);
+    subitem = proto_tree_add_item_ret_uint(subtree, hf->hf.hs_session_ticket_lifetime_hint,
+                                           tvb, offset, 4, ENC_BIG_ENDIAN, &lifetime_hint);
     offset += 4;
 
+    if (lifetime_hint >= 60) {
+        gchar *time_str = unsigned_time_secs_to_str(wmem_packet_scope(), lifetime_hint);
+        proto_item_append_text(subitem, " (%s)", time_str);
+    }
+
     if (is_tls13) {
 
         /* for TLS 1.3: ticket_age_add */
@@ -7023,7 +7502,7 @@ ssl_dissect_hnd_new_ses_ticket(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_i
             guint32 ticket_nonce_len;
 
             if (!ssl_add_vector(hf, tvb, pinfo, subtree, offset, offset_end, &ticket_nonce_len,
-                                hf->hf.hs_session_ticket_nonce_len, 1, 255)) {
+                                hf->hf.hs_session_ticket_nonce_len, 0, 255)) {
                 return;
             }
             offset++;
@@ -7078,18 +7557,24 @@ ssl_dissect_hnd_hello_retry_request(ssl_common_dissect_t *hf, tvbuff_t *tvb,
     /* https://tools.ietf.org/html/draft-ietf-tls-tls13-19#section-4.1.4
      * struct {
      *     ProtocolVersion server_version;
-     *     CipherSuite cipher_suite;
+     *     CipherSuite cipher_suite;        // not before draft -19
      *     Extension extensions<2..2^16-1>;
      * } HelloRetryRequest;
      */
-    proto_tree_add_item(tree, hf->hf.hs_server_version, tvb,
-                        offset, 2, ENC_BIG_ENDIAN);
-    offset += 2;
+    guint32     version;
+    guint8      draft_version;
 
-    proto_tree_add_item(tree, hf->hf.hs_cipher_suite,
-                        tvb, offset, 2, ENC_BIG_ENDIAN);
+    proto_tree_add_item_ret_uint(tree, hf->hf.hs_server_version, tvb,
+                                 offset, 2, ENC_BIG_ENDIAN, &version);
+    draft_version = tls13_draft_version(version);
     offset += 2;
 
+    if (draft_version == 0 || draft_version >= 19) {
+        proto_tree_add_item(tree, hf->hf.hs_cipher_suite,
+                            tvb, offset, 2, ENC_BIG_ENDIAN);
+        offset += 2;
+    }
+
     ssl_dissect_hnd_extension(hf, tvb, tree, pinfo, offset,
                               offset_end, SSL_HND_HELLO_RETRY_REQUEST,
                               session, ssl, is_dtls);
@@ -7314,6 +7799,15 @@ ssl_dissect_hnd_cert_req(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *p
      *        DistinguishedName certificate_authorities<0..2^16-1>;
      *    } CertificateRequest;
      *
+     * draft-ietf-tls-tls13-18:
+     *    struct {
+     *        opaque certificate_request_context<0..2^8-1>;
+     *        SignatureScheme
+     *          supported_signature_algorithms<2..2^16-2>;
+     *        DistinguishedName certificate_authorities<0..2^16-1>;
+     *        CertificateExtension certificate_extensions<0..2^16-1>;
+     *    } CertificateRequest;
+     *
      * draft-ietf-tls-tls13-19:
      *
      *    struct {
@@ -7325,13 +7819,15 @@ ssl_dissect_hnd_cert_req(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *p
     proto_tree *subtree;
     guint32     next_offset;
     asn1_ctx_t  asn1_ctx;
+    gboolean    is_tls13 = session->version == TLSV1DOT3_VERSION;
+    guchar      draft_version = session->tls13_draft_version;
 
     if (!tree)
         return;
 
     asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
 
-    if (session->version == TLSV1DOT3_VERSION) {
+    if (is_tls13) {
         guint32 context_length;
         /* opaque certificate_request_context<0..2^8-1> */
         if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &context_length,
@@ -7368,24 +7864,27 @@ ssl_dissect_hnd_cert_req(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *p
         }
     }
 
-    switch (session->version) {
-        case TLSV1DOT2_VERSION:
-        case DTLSV1DOT2_VERSION:
-            offset = ssl_dissect_hash_alg_list(hf, tvb, tree, pinfo, offset, offset_end);
-            break;
-
-        default:
-            break;
+    if (session->version == TLSV1DOT2_VERSION || session->version == DTLSV1DOT2_VERSION ||
+            (is_tls13 && (draft_version > 0 && draft_version < 19))) {
+        offset = ssl_dissect_hash_alg_list(hf, tvb, tree, pinfo, offset, offset_end);
     }
 
-    if (session->version == TLSV1DOT3_VERSION) {
+    if (is_tls13 && (draft_version == 0 || draft_version >= 19)) {
         /*
+         * TLS 1.3 draft 19 and newer: Extensions.
          * SslDecryptSession pointer is NULL because Certificate Extensions
          * should not influence decryption state.
          */
         ssl_dissect_hnd_extension(hf, tvb, tree, pinfo, offset,
                                   offset_end, SSL_HND_CERT_REQUEST,
                                   session, NULL, is_dtls);
+    } else if (is_tls13 && draft_version <= 18) {
+        /*
+         * TLS 1.3 draft 18 and older: certificate_authorities and
+         * certificate_extensions (a vector of OID mappings).
+         */
+        offset = tls_dissect_certificate_authorities(hf, tvb, pinfo, tree, offset, offset_end);
+        ssl_dissect_hnd_hello_ext_oid_filters(hf, tvb, pinfo, tree, offset, offset_end);
     } else {
         /* for TLS 1.2 and older, the certificate_authorities field. */
         tls_dissect_certificate_authorities(hf, tvb, pinfo, tree, offset, offset_end);
@@ -7512,6 +8011,7 @@ ssl_dissect_hnd_extension(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *t
     guint32     ext_len;
     guint32     next_offset;
     proto_tree *ext_tree;
+    gboolean    is_tls13 = session->version == TLSV1DOT3_VERSION;
 
     /* Extension extensions<0..2^16-2> (for TLS 1.3 HRR/CR min-length is 2) */
     if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &exts_len,
@@ -7548,9 +8048,11 @@ ssl_dissect_hnd_extension(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *t
             offset = ssl_dissect_hnd_hello_ext_server_name(hf, tvb, pinfo, ext_tree, offset, next_offset);
             break;
         case SSL_HND_HELLO_EXT_STATUS_REQUEST:
-            if (hnd_type == SSL_HND_CLIENT_HELLO)
-                offset = ssl_dissect_hnd_hello_ext_status_request(hf, tvb, ext_tree, offset, FALSE);
-            // TODO dissect CertificateStatus for SSL_HND_CERTIFICATE (TLS 1.3)
+            if (hnd_type == SSL_HND_CLIENT_HELLO) {
+                offset = ssl_dissect_hnd_hello_ext_status_request(hf, tvb, pinfo, ext_tree, offset, next_offset, FALSE);
+            } else if (is_tls13 && hnd_type == SSL_HND_CERTIFICATE) {
+                offset = tls_dissect_hnd_certificate_status(hf, tvb, pinfo, ext_tree, offset, next_offset);
+            }
             break;
         case SSL_HND_HELLO_EXT_CERT_TYPE:
             offset = ssl_dissect_hnd_hello_ext_cert_type(hf, tvb, ext_tree,
@@ -7565,6 +8067,7 @@ ssl_dissect_hnd_extension(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *t
             offset = ssl_dissect_hnd_hello_ext_ec_point_formats(hf, tvb, ext_tree, offset);
             break;
         case SSL_HND_HELLO_EXT_SIGNATURE_ALGORITHMS:
+        case SSL_HND_HELLO_EXT_SIGNATURE_ALGORITHMS_CERT: /* since TLS 1.3 draft -23 */
             offset = ssl_dissect_hnd_hello_ext_sig_hash_algs(hf, tvb, ext_tree, pinfo, offset, next_offset);
             break;
         case SSL_HND_HELLO_EXT_USE_SRTP:
@@ -7584,11 +8087,11 @@ ssl_dissect_hnd_extension(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *t
             break;
         case SSL_HND_HELLO_EXT_STATUS_REQUEST_V2:
             if (hnd_type == SSL_HND_CLIENT_HELLO)
-                offset = ssl_dissect_hnd_hello_ext_status_request_v2(hf, tvb, ext_tree, offset);
-            // TODO dissect CertificateStatus for SSL_HND_CERTIFICATE (TLS 1.3)
+                offset = ssl_dissect_hnd_hello_ext_status_request_v2(hf, tvb, pinfo, ext_tree, offset, next_offset);
             break;
         case SSL_HND_HELLO_EXT_SIGNED_CERTIFICATE_TIMESTAMP:
-            if (hnd_type == SSL_HND_SERVER_HELLO || hnd_type == SSL_HND_ENCRYPTED_EXTENSIONS)
+            // TLS 1.3 note: SCT only appears in EE in draft -16 and before.
+            if (hnd_type == SSL_HND_SERVER_HELLO || hnd_type == SSL_HND_ENCRYPTED_EXTENSIONS || hnd_type == SSL_HND_CERTIFICATE)
                 offset = tls_dissect_sct_list(hf, tvb, pinfo, ext_tree, offset, next_offset, session->version);
             break;
         case SSL_HND_HELLO_EXT_CLIENT_CERT_TYPE:
@@ -7622,9 +8125,13 @@ ssl_dissect_hnd_extension(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *t
                 }
             }
             break;
+        case SSL_HND_HELLO_EXT_QUIC_TRANSPORT_PARAMETERS:
+            offset = ssl_dissect_hnd_hello_ext_quic_transport_parameters(hf, tvb, pinfo, ext_tree, offset, next_offset, hnd_type, ssl);
+            break;
         case SSL_HND_HELLO_EXT_SESSION_TICKET_TLS:
             offset = ssl_dissect_hnd_hello_ext_session_ticket(hf, tvb, ext_tree, offset, next_offset, hnd_type, ssl);
             break;
+        case SSL_HND_HELLO_EXT_KEY_SHARE_OLD: /* used before TLS 1.3 draft -23 */
         case SSL_HND_HELLO_EXT_KEY_SHARE:
             offset = ssl_dissect_hnd_hello_ext_key_share(hf, tvb, pinfo, ext_tree, offset, next_offset, hnd_type);
             break;
@@ -7632,10 +8139,20 @@ ssl_dissect_hnd_extension(ssl_common_dissect_t *hf, tvbuff_t *tvb, proto_tree *t
             offset = ssl_dissect_hnd_hello_ext_pre_shared_key(hf, tvb, pinfo, ext_tree, offset, next_offset, hnd_type);
             break;
         case SSL_HND_HELLO_EXT_EARLY_DATA:
+        case SSL_HND_HELLO_EXT_TICKET_EARLY_DATA_INFO:
             offset = ssl_dissect_hnd_hello_ext_early_data(hf, tvb, pinfo, ext_tree, offset, next_offset, hnd_type, ssl);
             break;
         case SSL_HND_HELLO_EXT_SUPPORTED_VERSIONS:
-            offset = ssl_dissect_hnd_hello_ext_supported_versions(hf, tvb, pinfo, ext_tree, offset, next_offset);
+            switch (hnd_type) {
+            case SSL_HND_CLIENT_HELLO:
+                offset = ssl_dissect_hnd_hello_ext_supported_versions(hf, tvb, pinfo, ext_tree, offset, next_offset);
+                break;
+            case SSL_HND_SERVER_HELLO:
+            case SSL_HND_HELLO_RETRY_REQUEST:
+                proto_tree_add_item(ext_tree, hf->hf.hs_ext_supported_version, tvb, offset, 2, ENC_BIG_ENDIAN);
+                offset += 2;
+                break;
+            }
             break;
         case SSL_HND_HELLO_EXT_COOKIE:
             offset = ssl_dissect_hnd_hello_ext_cookie(hf, tvb, pinfo, ext_tree, offset, next_offset);
@@ -7812,22 +8329,12 @@ ssl_dissect_digitally_signed(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_inf
                              guint16 version, gint hf_sig_len, gint hf_sig)
 {
     guint32     sig_len;
-    proto_item *ti_algo;
-    proto_tree *ssl_algo_tree;
 
     switch (version) {
     case TLSV1DOT2_VERSION:
     case DTLSV1DOT2_VERSION:
-    case TLSV1DOT3_VERSION: /* XXX merge both fields into one SignatureScheme? */
-        ti_algo = proto_tree_add_item(tree, hf->hf.hs_sig_hash_alg, tvb,
-                                      offset, 2, ENC_BIG_ENDIAN);
-        ssl_algo_tree = proto_item_add_subtree(ti_algo, hf->ett.hs_sig_hash_alg);
-
-        /* SignatureAndHashAlgorithm { hash, signature } */
-        proto_tree_add_item(ssl_algo_tree, hf->hf.hs_sig_hash_hash, tvb,
-                            offset, 1, ENC_BIG_ENDIAN);
-        proto_tree_add_item(ssl_algo_tree, hf->hf.hs_sig_hash_sig, tvb,
-                            offset + 1, 1, ENC_BIG_ENDIAN);
+    case TLSV1DOT3_VERSION:
+        tls_dissect_signature_algorithm(hf, tvb, tree, offset);
         offset += 2;
         break;