* 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)
{ 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" },
{ 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 */
{ 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 */
{ 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" },
{ "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
/* StringInfo structure (len + data) functions {{{ */
-static gint
+gint
ssl_data_alloc(StringInfo* str, size_t len)
{
str->data = (guchar *)g_malloc(len);
gcry_cipher_close(*cipher);
*cipher = NULL;
}
+/* }}} */
/* Digests, Ciphers and Cipher Suites registry {{{ */
static const SslDigestAlgo digests[]={
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 }}} */
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 {{{ */
}
/* 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;
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;
}
#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)
/* 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*/
* @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);
/* 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;
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);
}
} /* }}} */
-/* 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) {
} 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
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;
/* 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;
}
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){
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.
}
/** 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. {{{ */
* } 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;
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;
}
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)) {
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, ¶meter_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, ¶meter_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);
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,
}
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);
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;
}
}
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;
* 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);
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:
return;
}
+ session->tls13_draft_version = tls13_draft;
session->version = version;
if (ssl) {
ssl->state |= SSL_VERSION;
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) {
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;
* 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
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 */
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);
/* 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);
}
}
* 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 */
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++;
/* 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);
* 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 {
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,
}
}
- 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);
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,
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,
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:
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:
}
}
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;
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);
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;