* 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 <epan/expert.h>
#include <epan/asn1.h>
#include <epan/proto_data.h>
+#include <epan/oids.h>
#include <wsutil/filesystem.h>
#include <wsutil/file_util.h>
#include <wsutil/str_util.h>
-#include <wsutil/report_err.h>
+#include <wsutil/report_message.h>
#include <wsutil/pint.h>
#include <wsutil/strtoi.h>
-#include <ws_version_info.h>
+#include <wsutil/wsgcrypt.h>
+#include <wsutil/rsa.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)
/* Whether to provide support for authentication in addition to decryption. */
#define HAVE_LIBGCRYPT_AEAD
#endif
+#if GCRYPT_VERSION_NUMBER >= 0x010700 /* 1.7.0 */
+/* Whether AEAD_CHACHA20_POLY1305 can be supported. */
+#define HAVE_LIBGCRYPT_CHACHA20_POLY1305
+#endif
/* Lookup tables {{{ */
const value_string ssl_version_short_names[] = {
{ 0x7F11, "TLS 1.3 (draft 17)" },
{ 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" },
{ 26, "brainpoolP256r1" }, /* RFC 7027 */
{ 27, "brainpoolP384r1" }, /* RFC 7027 */
{ 28, "brainpoolP512r1" }, /* RFC 7027 */
- { 29, "ecdh_x25519" }, /* https://tools.ietf.org/html/draft-ietf-tls-rfc4492bis */
- { 30, "ecdh_x448" }, /* https://tools.ietf.org/html/draft-ietf-tls-rfc4492bis */
+ { 29, "x25519" }, /* https://tools.ietf.org/html/draft-ietf-tls-tls13 https://tools.ietf.org/html/draft-ietf-tls-rfc4492bis */
+ { 30, "x448" }, /* https://tools.ietf.org/html/draft-ietf-tls-tls13 https://tools.ietf.org/html/draft-ietf-tls-rfc4492bis */
{ 256, "ffdhe2048" }, /* RFC 7919 */
{ 257, "ffdhe3072" }, /* RFC 7919 */
{ 258, "ffdhe4096" }, /* RFC 7919 */
{ 259, "ffdhe6144" }, /* RFC 7919 */
{ 260, "ffdhe8192" }, /* RFC 7919 */
+ { 2570, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 6682, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 10794, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 14906, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 19018, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 23130, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 27242, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 31354, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 35466, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 39578, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 43690, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 47802, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 51914, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 56026, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 60138, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
+ { 64250, "Reserved (GREASE)" }, /* draft-ietf-tls-grease */
{ 0xFF01, "arbitrary_explicit_prime_curves" },
{ 0xFF02, "arbitrary_explicit_char2_curves" },
{ 0x00, NULL }
{ SSL_HND_SERVER_HELLO, "Server Hello" },
{ SSL_HND_HELLO_VERIFY_REQUEST, "Hello Verify Request"},
{ SSL_HND_NEWSESSION_TICKET, "New Session Ticket" },
+ { SSL_HND_END_OF_EARLY_DATA, "End of Early Data" },
{ SSL_HND_HELLO_RETRY_REQUEST, "Hello Retry Request" },
{ SSL_HND_ENCRYPTED_EXTENSIONS, "Encrypted Extensions" },
{ SSL_HND_CERTIFICATE, "Certificate" },
of the ietf-tls list */
{ 0x001e, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA" },
#endif
-
/* RFC 2712 */
{ 0x001E, "TLS_KRB5_WITH_DES_CBC_SHA" },
{ 0x001F, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA" },
{ 0x0029, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5" },
{ 0x002A, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5" },
{ 0x002B, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5" },
-
/* RFC 4785 */
{ 0x002C, "TLS_PSK_WITH_NULL_SHA" },
{ 0x002D, "TLS_DHE_PSK_WITH_NULL_SHA" },
{ 0x002E, "TLS_RSA_PSK_WITH_NULL_SHA" },
-
/* RFC 5246 */
{ 0x002F, "TLS_RSA_WITH_AES_128_CBC_SHA" },
{ 0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA" },
{ 0x003E, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256" },
{ 0x003F, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256" },
{ 0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256" },
-
/* RFC 4132 */
{ 0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA" },
{ 0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA" },
{ 0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA" },
{ 0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA" },
{ 0x0046, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA" },
-
/* 0x00,0x60-66 Reserved to avoid conflicts with widely deployed implementations */
/* --- ??? --- */
{ 0x0060, "TLS_RSA_EXPORT1024_WITH_RC4_56_MD5" },
{ 0x0065, "TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA" },
{ 0x0066, "TLS_DHE_DSS_WITH_RC4_128_SHA" },
/* --- ??? ---*/
-
{ 0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256" },
{ 0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256" },
{ 0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256" },
{ 0x006B, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256" },
{ 0x006C, "TLS_DH_anon_WITH_AES_128_CBC_SHA256" },
{ 0x006D, "TLS_DH_anon_WITH_AES_256_CBC_SHA256" },
-
/* draft-chudov-cryptopro-cptls-04.txt */
{ 0x0080, "TLS_GOSTR341094_WITH_28147_CNT_IMIT" },
{ 0x0081, "TLS_GOSTR341001_WITH_28147_CNT_IMIT" },
{ 0x0082, "TLS_GOSTR341094_WITH_NULL_GOSTR3411" },
{ 0x0083, "TLS_GOSTR341001_WITH_NULL_GOSTR3411" },
-
/* RFC 4132 */
{ 0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA" },
{ 0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA" },
{ 0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA" },
{ 0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA" },
{ 0x0089, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA" },
-
/* RFC 4279 */
{ 0x008A, "TLS_PSK_WITH_RC4_128_SHA" },
{ 0x008B, "TLS_PSK_WITH_3DES_EDE_CBC_SHA" },
{ 0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA" },
{ 0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA" },
{ 0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA" },
-
/* RFC 4162 */
{ 0x0096, "TLS_RSA_WITH_SEED_CBC_SHA" },
{ 0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA" },
{ 0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA" },
{ 0x009A, "TLS_DHE_RSA_WITH_SEED_CBC_SHA" },
{ 0x009B, "TLS_DH_anon_WITH_SEED_CBC_SHA" },
-
/* RFC 5288 */
{ 0x009C, "TLS_RSA_WITH_AES_128_GCM_SHA256" },
{ 0x009D, "TLS_RSA_WITH_AES_256_GCM_SHA384" },
{ 0x00A5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384" },
{ 0x00A6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256" },
{ 0x00A7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384" },
-
/* RFC 5487 */
{ 0x00A8, "TLS_PSK_WITH_AES_128_GCM_SHA256" },
{ 0x00A9, "TLS_PSK_WITH_AES_256_GCM_SHA384" },
{ 0x00B7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384" },
{ 0x00B8, "TLS_RSA_PSK_WITH_NULL_SHA256" },
{ 0x00B9, "TLS_RSA_PSK_WITH_NULL_SHA384" },
-
/* From RFC 5932 */
{ 0x00BA, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256" },
{ 0x00BB, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256" },
/* 0x00,0xC6-FE Unassigned */
/* From RFC 5746 */
{ 0x00FF, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" },
+ /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { 0x0A0A, "Reserved (GREASE)" },
/* https://tools.ietf.org/html/draft-ietf-tls-tls13 */
{ 0x1301, "TLS_AES_128_GCM_SHA256" },
{ 0x1302, "TLS_AES_256_GCM_SHA384" },
{ 0x1303, "TLS_CHACHA20_POLY1305_SHA256" },
{ 0x1304, "TLS_AES_128_CCM_SHA256" },
{ 0x1305, "TLS_AES_128_CCM_8_SHA256" },
+ /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { 0x1A1A, "Reserved (GREASE)" },
+ { 0x2A2A, "Reserved (GREASE)" },
+ { 0x3A3A, "Reserved (GREASE)" },
+ { 0x4A4A, "Reserved (GREASE)" },
/* From RFC 7507 */
{ 0x5600, "TLS_FALLBACK_SCSV" },
+ /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { 0x5A5A, "Reserved (GREASE)" },
+ { 0x6A6A, "Reserved (GREASE)" },
+ { 0x7A7A, "Reserved (GREASE)" },
+ { 0x8A8A, "Reserved (GREASE)" },
+ { 0x9A9A, "Reserved (GREASE)" },
+ { 0xAAAA, "Reserved (GREASE)" },
+ { 0xBABA, "Reserved (GREASE)" },
/* From RFC 4492 */
{ 0xc001, "TLS_ECDH_ECDSA_WITH_NULL_SHA" },
{ 0xc002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA" },
{ 0xc017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA" },
{ 0xc018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA" },
{ 0xc019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA" },
-
/* RFC 5054 */
{ 0xC01A, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA" },
{ 0xC01B, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA" },
{ 0xC020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA" },
{ 0xC021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA" },
{ 0xC022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA" },
-
/* RFC 5589 */
{ 0xC023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256" },
{ 0xC024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384" },
{ 0xC030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" },
{ 0xC031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256" },
{ 0xC032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384" },
-
/* RFC 5489 */
{ 0xC033, "TLS_ECDHE_PSK_WITH_RC4_128_SHA" },
{ 0xC034, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA" },
{ 0xC039, "TLS_ECDHE_PSK_WITH_NULL_SHA" },
{ 0xC03A, "TLS_ECDHE_PSK_WITH_NULL_SHA256" },
{ 0xC03B, "TLS_ECDHE_PSK_WITH_NULL_SHA384" },
-
/* RFC 6209 */
{ 0xC03C, "TLS_RSA_WITH_ARIA_128_CBC_SHA256" },
{ 0xC03D, "TLS_RSA_WITH_ARIA_256_CBC_SHA384" },
{ 0xC06F, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384" },
{ 0xC070, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256" },
{ 0xC071, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384" },
-
/* RFC 6367 */
{ 0xC072, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256" },
{ 0xC073, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384" },
{ 0xC099, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384" },
{ 0xC09A, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256" },
{ 0xC09B, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384" },
-
/* RFC 6655 */
{ 0xC09C, "TLS_RSA_WITH_AES_128_CCM" },
{ 0xC09D, "TLS_RSA_WITH_AES_256_CCM" },
{ 0xC0A9, "TLS_PSK_WITH_AES_256_CCM_8" },
{ 0xC0AA, "TLS_PSK_DHE_WITH_AES_128_CCM_8" },
{ 0xC0AB, "TLS_PSK_DHE_WITH_AES_256_CCM_8" },
-
/* RFC 7251 */
{ 0xC0AC, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM" },
{ 0xC0AD, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM" },
{ 0xC0AE, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8" },
{ 0xC0AF, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8" },
+ /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { 0xCACA, "Reserved (GREASE)" },
/*
0xC0,0xAB-FF Unassigned
0xC1-FD,* Unassigned
0xFE,0xFE-FF Reserved to avoid conflicts with widely deployed implementations [Pasi_Eronen]
0xFF,0x00-FF Reserved for Private Use [RFC5246]
*/
-
/* old numbers used in the beginning
* http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305 */
{ 0xCC13, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" },
{ 0xCC14, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" },
{ 0xCC15, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256" },
-
- /* http://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305 */
+ /* RFC 7905 */
{ 0xCCA8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" },
{ 0xCCA9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" },
{ 0xCCAA, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256" },
{ 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 */
{ 0xE410, "TLS_RSA_WITH_ESTREAM_SALSA20_SHA1" },
{ 0xE411, "TLS_RSA_WITH_SALSA20_SHA1" },
{ 0xE41D, "TLS_DHE_PSK_WITH_SALSA20_SHA1" },
{ 0xE41E, "TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1" },
{ 0xE41F, "TLS_DHE_RSA_WITH_SALSA20_SHA1" },
-
+ /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { 0xEAEA, "Reserved (GREASE)" },
+ { 0xFAFA, "Reserved (GREASE)" },
/* these from http://www.mozilla.org/projects/
security/pki/nss/ssl/fips-ssl-ciphersuites.html */
{ 0xfefe, "SSL_RSA_FIPS_WITH_DES_CBC_SHA"},
{ 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 */
{ SSL_HND_HELLO_EXT_NPN, "next_protocol_negotiation"}, /* https://tools.ietf.org/id/draft-agl-tls-nextprotoneg-03.html */
+ { SSL_HND_HELLO_EXT_GREASE_3A3A, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { SSL_HND_HELLO_EXT_GREASE_4A4A, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { SSL_HND_HELLO_EXT_GREASE_5A5A, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { SSL_HND_HELLO_EXT_GREASE_6A6A, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
{ SSL_HND_HELLO_EXT_CHANNEL_ID_OLD, "channel_id_old" }, /* http://tools.ietf.org/html/draft-balfanz-tls-channelid-00
https://twitter.com/ericlaw/status/274237352531083264 */
{ SSL_HND_HELLO_EXT_CHANNEL_ID, "channel_id" }, /* http://tools.ietf.org/html/draft-balfanz-tls-channelid-01
https://code.google.com/p/chromium/codesearch#chromium/src/net/third_party/nss/ssl/sslt.h&l=209 */
{ SSL_HND_HELLO_EXT_RENEGOTIATION_INFO, "renegotiation_info" }, /* RFC 5746 */
+ { SSL_HND_HELLO_EXT_GREASE_7A7A, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { SSL_HND_HELLO_EXT_GREASE_8A8A, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { SSL_HND_HELLO_EXT_GREASE_9A9A, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { SSL_HND_HELLO_EXT_GREASE_AAAA, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { SSL_HND_HELLO_EXT_GREASE_BABA, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { SSL_HND_HELLO_EXT_GREASE_CACA, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { SSL_HND_HELLO_EXT_GREASE_DADA, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { SSL_HND_HELLO_EXT_GREASE_EAEA, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
+ { SSL_HND_HELLO_EXT_GREASE_FAFA, "Reserved (GREASE)" }, /* https://tools.ietf.org/html/draft-ietf-tls-grease */
{ SSL_HND_HELLO_EXT_DRAFT_VERSION_TLS13, "Draft version of TLS 1.3" }, /* for experimentation only https://www.ietf.org/mail-archive/web/tls/current/msg20853.html */
{ 0, NULL }
};
{ 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
case 0xc0a7:
case 0xc0aa:
case 0xc0ab:
+ case 0xccad:
case 0xe41c:
case 0xe41d:
return KEX_DHE_PSK;
case 0xc09f:
case 0xc0a2:
case 0xc0a3:
+ case 0xccaa:
case 0xe41e:
case 0xe41f:
return KEX_DHE_RSA;
case 0xc0ad:
case 0xc0ae:
case 0xc0af:
+ case 0xcca9:
case 0xe414:
case 0xe415:
return KEX_ECDHE_ECDSA;
case 0xc03b:
case 0xc09a:
case 0xc09b:
+ case 0xccac:
case 0xe418:
case 0xe419:
return KEX_ECDHE_PSK;
case 0xc077:
case 0xc08a:
case 0xc08b:
+ case 0xcca8:
case 0xe412:
case 0xe413:
return KEX_ECDHE_RSA;
case 0xc0a5:
case 0xc0a8:
case 0xc0a9:
+ case 0xccab:
case 0xe416:
case 0xe417:
return KEX_PSK;
case 0xc093:
case 0xc098:
case 0xc099:
+ case 0xccae:
case 0xe41a:
case 0xe41b:
return KEX_RSA_PSK;
/* StringInfo structure (len + data) functions {{{ */
-static gint
+gint
ssl_data_alloc(StringInfo* str, size_t len)
{
str->data = (guchar *)g_malloc(len);
#ifdef HAVE_LIBGCRYPT_AEAD
GCRY_CIPHER_MODE_GCM,
GCRY_CIPHER_MODE_CCM,
- GCRY_CIPHER_MODE_CCM
+ GCRY_CIPHER_MODE_CCM,
#else
GCRY_CIPHER_MODE_CTR,
GCRY_CIPHER_MODE_CTR,
GCRY_CIPHER_MODE_CTR,
+#endif
+#ifdef HAVE_LIBGCRYPT_CHACHA20_POLY1305
+ GCRY_CIPHER_MODE_POLY1305,
+#else
+ -1, /* AEAD_CHACHA20_POLY1305 is unsupported. */
#endif
};
gint err;
gcry_cipher_close(*cipher);
*cipher = NULL;
}
-/* libgcrypt wrappers for Cipher state manipulation }}} */
-
-#ifdef HAVE_LIBGNUTLS
-/* libgcrypt wrapper to decrypt using a RSA private key {{{ */
-/* decrypt data with private key. Store decrypted data directly into input
- * buffer */
-static int
-ssl_private_decrypt(const guint len, guchar* data, gcry_sexp_t pk)
-{
- gint rc = 0;
- size_t decr_len = 0, i = 0;
- gcry_sexp_t s_data = NULL, s_plain = NULL;
- gcry_mpi_t encr_mpi = NULL, text = NULL;
-
- /* create mpi representation of encrypted data */
- rc = gcry_mpi_scan(&encr_mpi, GCRYMPI_FMT_USG, data, len, NULL);
- if (rc != 0 ) {
- ssl_debug_printf("pcry_private_decrypt: can't convert data to mpi (size %d):%s\n",
- len, gcry_strerror(rc));
- return 0;
- }
-
- /* put the data into a simple list */
- rc = gcry_sexp_build(&s_data, NULL, "(enc-val(rsa(a%m)))", encr_mpi);
- if (rc != 0) {
- ssl_debug_printf("pcry_private_decrypt: can't build encr_sexp:%s\n",
- gcry_strerror(rc));
- decr_len = 0;
- goto out;
- }
-
- /* pass it to libgcrypt */
- rc = gcry_pk_decrypt(&s_plain, s_data, pk);
- if (rc != 0)
- {
- ssl_debug_printf("pcry_private_decrypt: can't decrypt key:%s\n",
- gcry_strerror(rc));
- decr_len = 0;
- goto out;
- }
-
- /* convert plain text sexp to mpi format */
- text = gcry_sexp_nth_mpi(s_plain, 0, 0);
- if (! text) {
- ssl_debug_printf("pcry_private_decrypt: can't convert sexp to mpi\n");
- decr_len = 0;
- goto out;
- }
-
- /* compute size requested for plaintext buffer */
- rc = gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &decr_len, text);
- if (rc != 0) {
- ssl_debug_printf("pcry_private_decrypt: can't compute decr size:%s\n",
- gcry_strerror(rc));
- decr_len = 0;
- goto out;
- }
-
- /* sanity check on out buffer */
- if (decr_len > len) {
- ssl_debug_printf("pcry_private_decrypt: decrypted data is too long ?!? (%" G_GSIZE_MODIFIER "u max %d)\n", decr_len, len);
- decr_len = 0;
- goto out;
- }
-
- /* write plain text to newly allocated buffer */
- rc = gcry_mpi_print(GCRYMPI_FMT_USG, data, len, &decr_len, text);
- if (rc != 0) {
- ssl_debug_printf("pcry_private_decrypt: can't print decr data to mpi (size %" G_GSIZE_MODIFIER "u):%s\n", decr_len, gcry_strerror(rc));
- decr_len = 0;
- goto out;
- }
-
- ssl_print_data("decrypted_unstrip_pre_master", data, decr_len);
-
- /* strip the padding*/
- rc = 0;
- for (i = 1; i < decr_len; i++) {
- if (data[i] == 0) {
- rc = (gint) i+1;
- break;
- }
- }
-
- ssl_debug_printf("pcry_private_decrypt: stripping %d bytes, decr_len %" G_GSIZE_MODIFIER "u\n", rc, decr_len);
- decr_len -= rc;
- memmove(data, data+rc, decr_len);
-
-out:
- gcry_sexp_release(s_data);
- gcry_sexp_release(s_plain);
- gcry_mpi_release(encr_mpi);
- gcry_mpi_release(text);
- return (int) decr_len;
-} /* }}} */
-#endif /* HAVE_LIBGNUTLS */
-
+/* }}} */
/* Digests, Ciphers and Cipher Suites registry {{{ */
static const SslDigestAlgo digests[]={
"CAMELLIA128",
"CAMELLIA256",
"SEED",
+ "CHACHA20", /* since Libgcrypt 1.7.0 */
"*UNKNOWN*"
};
/* NOTE: TLS 1.3 cipher suites are incompatible with TLS 1.2. */
{0x1301,KEX_TLS13, ENC_AES, DIG_SHA256, MODE_GCM }, /* TLS_AES_128_GCM_SHA256 */
{0x1302,KEX_TLS13, ENC_AES256, DIG_SHA384, MODE_GCM }, /* TLS_AES_256_GCM_SHA384 */
- /* TODO TLS_CHACHA20_POLY1305_SHA256 */
+ {0x1303,KEX_TLS13, ENC_CHACHA20, DIG_SHA256, MODE_POLY1305 }, /* TLS_CHACHA20_POLY1305_SHA256 */
{0x1304,KEX_TLS13, ENC_AES, DIG_SHA256, MODE_CCM }, /* TLS_AES_128_CCM_SHA256 */
{0x1305,KEX_TLS13, ENC_AES, DIG_SHA256, MODE_CCM_8 }, /* TLS_AES_128_CCM_8_SHA256 */
{0xC0AD,KEX_ECDHE_ECDSA, ENC_AES256, DIG_NA, MODE_CCM }, /* TLS_ECDHE_ECDSA_WITH_AES_256_CCM */
{0xC0AE,KEX_ECDHE_ECDSA, ENC_AES, DIG_NA, MODE_CCM_8 }, /* TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */
{0xC0AF,KEX_ECDHE_ECDSA, ENC_AES256, DIG_NA, MODE_CCM_8 }, /* TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 */
+ {0xCCA8,KEX_ECDHE_RSA, ENC_CHACHA20, DIG_SHA256, MODE_POLY1305 }, /* TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 */
+ {0xCCA9,KEX_ECDHE_ECDSA, ENC_CHACHA20, DIG_SHA256, MODE_POLY1305 }, /* TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 */
+ {0xCCAA,KEX_DHE_RSA, ENC_CHACHA20, DIG_SHA256, MODE_POLY1305 }, /* TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 */
+ {0xCCAB,KEX_PSK, ENC_CHACHA20, DIG_SHA256, MODE_POLY1305 }, /* TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 */
+ {0xCCAC,KEX_ECDHE_PSK, ENC_CHACHA20, DIG_SHA256, MODE_POLY1305 }, /* TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 */
+ {0xCCAD,KEX_DHE_PSK, ENC_CHACHA20, DIG_SHA256, MODE_POLY1305 }, /* TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 */
+ {0xCCAE,KEX_RSA_PSK, ENC_CHACHA20, DIG_SHA256, MODE_POLY1305 }, /* TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 */
{-1, 0, 0, 0, MODE_STREAM}
};
return 0;
}
-static gboolean
-tls13_hkdf_expand_label(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-18:
- * 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<9..255> = "TLS 1.3, " + 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 <= 255 - 9);
- 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;
- }
-
- *out = (guchar *)wmem_alloc(NULL, out_len);
+ DISSECTOR_ASSERT(label_length > 0 && label_prefix_length + label_length <= 255);
- 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);
- gcry_md_putc(h, 9 + label_length); /* label */
- gcry_md_write(h, "TLS 1.3, ", 9);
- 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 }}} */
// decoders since "decryption" is easy for such ciphers.
dec->mac_key.data = dec->_mac_key_or_write_iv;
ssl_data_set(&dec->mac_key, mk, ssl_cipher_suite_dig(cipher_suite)->len);
- } else if (mode == MODE_GCM || mode == MODE_CCM || mode == MODE_CCM_8) {
+ } else if (mode == MODE_GCM || mode == MODE_CCM || mode == MODE_CCM_8 || mode == MODE_POLY1305) {
// Input for the nonce, to be used with AEAD ciphers.
DISSECTOR_ASSERT(iv_length <= sizeof(dec->_mac_key_or_write_iv));
dec->write_iv.data = dec->_mac_key_or_write_iv;
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 {{{ */
/* account for a four-byte salt for client and server side (from
* client_write_IV and server_write_IV), see GCMNonce (RFC 5288) */
write_iv_len = 4;
+ } else if (cipher_suite->mode == MODE_POLY1305) {
+ /* RFC 7905: SecurityParameters.fixed_iv_length is twelve bytes */
+ write_iv_len = 12;
}
/* Compute the key block. First figure out how much data we need */
}
/* 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;
return FALSE;
}
- key_length = (guint) gcry_cipher_get_algo_blklen(cipher_algo);
+ key_length = (guint) gcry_cipher_get_algo_keylen(cipher_algo);
/* AES-GCM/AES-CCM/Poly1305-ChaCha20 all have N_MIN=N_MAX = 12. */
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(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(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;
}
ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session,
StringInfo* encrypted_pre_master, gcry_sexp_t pk)
{
- gint i;
+ size_t i;
+ char *err;
if (!encrypted_pre_master)
return FALSE;
/* with tls key loading will fail if not rsa type, so no need to check*/
ssl_print_string("pre master encrypted",encrypted_pre_master);
ssl_debug_printf("%s: RSA_private_decrypt\n", G_STRFUNC);
- i=ssl_private_decrypt(encrypted_pre_master->data_len,
- encrypted_pre_master->data, pk);
+ i=rsa_decrypt_inplace(encrypted_pre_master->data_len,
+ encrypted_pre_master->data, pk, TRUE, &err);
+ if (i == 0) {
+ ssl_debug_printf("rsa_decrypt_inplace: %s\n", err);
+ g_free(err);
+ }
if (i!=48) {
- ssl_debug_printf("%s wrong pre_master_secret length (%d, expected "
+ ssl_debug_printf("%s wrong pre_master_secret length (%zd, expected "
"%d)\n", G_STRFUNC, i, 48);
return FALSE;
}
const guchar *explicit_nonce = NULL, *ciphertext;
guint ciphertext_len, auth_tag_len;
guchar nonce[12];
+ const ssl_cipher_mode_t cipher_mode = decoder->cipher_suite->mode;
#ifdef HAVE_LIBGCRYPT_AEAD
const guchar *auth_tag_wire;
guchar auth_tag_calc[16];
guchar nonce_with_counter[16] = { 0 };
#endif
- switch (decoder->cipher_suite->mode) {
+ switch (cipher_mode) {
case MODE_GCM:
case MODE_CCM:
+ case MODE_POLY1305:
auth_tag_len = 16;
break;
case MODE_CCM_8:
}
/* Parse input into explicit nonce (TLS 1.2 only), ciphertext and tag. */
- if (is_v12) {
+ if (is_v12 && cipher_mode != MODE_POLY1305) {
if (inl < EXPLICIT_NONCE_LEN + auth_tag_len) {
ssl_debug_printf("%s input %d is too small for explicit nonce %d and auth tag %d\n",
G_STRFUNC, inl, EXPLICIT_NONCE_LEN, auth_tag_len);
explicit_nonce = in;
ciphertext = explicit_nonce + EXPLICIT_NONCE_LEN;
ciphertext_len = inl - EXPLICIT_NONCE_LEN - auth_tag_len;
- } else if (version == TLSV1DOT3_VERSION) {
+ } else if (version == TLSV1DOT3_VERSION || cipher_mode == MODE_POLY1305) {
if (inl < auth_tag_len) {
ssl_debug_printf("%s input %d has no space for auth tag %d\n", G_STRFUNC, inl, auth_tag_len);
return FALSE;
auth_tag_wire = ciphertext + ciphertext_len;
#endif
- /* Nonce construction is version-specific. */
- if (is_v12) {
+ /*
+ * Nonce construction is version-specific. Note that AEAD_CHACHA20_POLY1305
+ * (RFC 7905) uses a nonce construction similar to TLS 1.3.
+ */
+ if (is_v12 && cipher_mode != MODE_POLY1305) {
DISSECTOR_ASSERT(decoder->write_iv.data_len == IMPLICIT_NONCE_LEN);
/* Implicit (4) and explicit (8) part of nonce. */
memcpy(nonce, decoder->write_iv.data, IMPLICIT_NONCE_LEN);
memcpy(nonce + IMPLICIT_NONCE_LEN, explicit_nonce, EXPLICIT_NONCE_LEN);
#ifndef HAVE_LIBGCRYPT_AEAD
- if (decoder->cipher_suite->mode == MODE_GCM) {
+ if (cipher_mode == MODE_GCM) {
/* NIST SP 800-38D, sect. 7.2 says that the 32-bit counter part starts
* at 1, and gets incremented before passing to the block cipher. */
memcpy(nonce_with_counter, nonce, IMPLICIT_NONCE_LEN + EXPLICIT_NONCE_LEN);
nonce_with_counter[IMPLICIT_NONCE_LEN + EXPLICIT_NONCE_LEN + 3] = 2;
- } else { /* MODE_CCM and MODE_CCM_8 */
+ } else if (cipher_mode == MODE_CCM || cipher_mode == MODE_CCM_8) {
/* The nonce for CCM and GCM are the same, but the nonce is used as input
* in the CCM algorithm described in RFC 3610. The nonce generated here is
* the one from RFC 3610 sect 2.3. Encryption. */
memcpy(nonce_with_counter + 1, nonce, IMPLICIT_NONCE_LEN + EXPLICIT_NONCE_LEN);
/* struct { opaque salt[4]; opaque nonce_explicit[8] } CCMNonce (RFC 6655) */
nonce_with_counter[IMPLICIT_NONCE_LEN + EXPLICIT_NONCE_LEN + 3] = 1;
+ } else {
+ g_assert_not_reached();
}
#endif
- } else if (version == TLSV1DOT3_VERSION) {
+ } else if (version == TLSV1DOT3_VERSION || cipher_mode == MODE_POLY1305) {
/*
* Technically the nonce length must be at least 8 bytes, but for
* AES-GCM, AES-CCM and Poly1305-ChaCha20 the nonce length is exact 12.
/* Sequence number is left-padded with zeroes and XORed with write_iv */
phton64(nonce + nonce_len - 8, pntoh64(nonce + nonce_len - 8) ^ decoder->seq);
ssl_debug_printf("%s seq %" G_GUINT64_FORMAT "\n", G_STRFUNC, decoder->seq);
- decoder->seq++; /* Implicit sequence number for TLS 1.3. */
+ /* sequence number for TLS 1.2 is incremented when calculating AAD. */
+ if (!is_v12) {
+ decoder->seq++; /* Implicit sequence number for TLS 1.3. */
+ }
}
/* Set nonce and additional authentication data */
ssl_decrypt_record(SslDecryptSession *ssl, SslDecoder *decoder, guint8 ct, guint16 record_version,
const guchar *in, guint16 inl, StringInfo *comp_str, StringInfo *out_str, guint *outl)
{
- guint pad, worklen, uncomplen;
- guint8 *mac;
+ guint pad, worklen, uncomplen, maclen, mac_fraglen = 0;
+ guint8 *mac = NULL, *mac_frag = NULL;
ssl_debug_printf("ssl_decrypt_record ciphertext len %d\n", inl);
ssl_print_data("Ciphertext",in, inl);
if (decoder->cipher_suite->mode == MODE_GCM ||
decoder->cipher_suite->mode == MODE_CCM ||
decoder->cipher_suite->mode == MODE_CCM_8 ||
+ decoder->cipher_suite->mode == MODE_POLY1305 ||
ssl->session.version == TLSV1DOT3_VERSION) {
if (!tls_decrypt_aead_record(ssl, decoder, ct, record_version, in, inl, out_str, &worklen)) {
* RFC 6347 (DTLS 1.2): based on TLS 1.2, includes GenericAEADCipher too.
*/
+ maclen = ssl_cipher_suite_dig(decoder->cipher_suite)->len;
+
/* (TLS 1.1 and later, DTLS) Extract explicit IV for GenericBlockCipher */
if (decoder->cipher_suite->mode == MODE_CBC) {
- guint blocksize;
+ guint blocksize = 0;
switch (ssl->session.version) {
case TLSV1DOT1_VERSION:
in += blocksize;
break;
}
+
+ /* Encrypt-then-MAC for (D)TLS (RFC 7366) */
+ if (ssl->state & SSL_ENCRYPT_THEN_MAC) {
+ /*
+ * MAC is calculated over (IV + ) ENCRYPTED contents:
+ *
+ * MAC(MAC_write_key, ... +
+ * IV + // for TLS 1.1 or greater
+ * TLSCiphertext.enc_content);
+ */
+ if (inl < maclen) {
+ ssl_debug_printf("%s failed: input %d has no space for MAC %d\n",
+ G_STRFUNC, inl, maclen);
+ return -1;
+ }
+ inl -= maclen;
+ mac = (guint8 *)in + inl;
+ mac_frag = (guint8 *)in - blocksize;
+ mac_fraglen = blocksize + inl;
+ }
}
/* First decrypt*/
pad, worklen);
}
- /* MAC for GenericStreamCipher and GenericBlockCipher */
- if (ssl_cipher_suite_dig(decoder->cipher_suite)->len > (gint)worklen) {
- ssl_debug_printf("ssl_decrypt_record wrong record len/padding outlen %d\n work %d\n",*outl, worklen);
- return -1;
+ /* MAC for GenericStreamCipher and GenericBlockCipher.
+ * (normal case without Encrypt-then-MAC (RFC 7366) extension. */
+ if (!mac) {
+ /*
+ * MAC is calculated over the DECRYPTED contents:
+ *
+ * MAC(MAC_write_key, ... + TLSCompressed.fragment);
+ */
+ if (worklen < maclen) {
+ ssl_debug_printf("%s wrong record len/padding outlen %d\n work %d\n", G_STRFUNC, *outl, worklen);
+ return -1;
+ }
+ worklen -= maclen;
+ mac = out_str->data + worklen;
+ mac_frag = out_str->data;
+ mac_fraglen = worklen;
}
- worklen -= ssl_cipher_suite_dig(decoder->cipher_suite)->len;
- mac = out_str->data + worklen;
/* If NULL encryption active and no keys are available, do not bother
* checking the MAC. We do not have keys for that. */
ssl_debug_printf("checking mac (len %d, version %X, ct %d seq %" G_GUINT64_FORMAT ")\n",
worklen, ssl->session.version, ct, decoder->seq);
if(ssl->session.version==SSLV3_VERSION){
- if(ssl3_check_mac(decoder,ct,out_str->data,worklen,mac) < 0) {
+ if(ssl3_check_mac(decoder,ct,mac_frag,mac_fraglen,mac) < 0) {
if(ssl_ignore_mac_failed) {
ssl_debug_printf("ssl_decrypt_record: mac failed, but ignored for troubleshooting ;-)\n");
}
}
}
else if(ssl->session.version==TLSV1_VERSION || ssl->session.version==TLSV1DOT1_VERSION || ssl->session.version==TLSV1DOT2_VERSION){
- if(tls_check_mac(decoder,ct,ssl->session.version,out_str->data,worklen,mac)< 0) {
+ if(tls_check_mac(decoder,ct,ssl->session.version,mac_frag,mac_fraglen,mac)< 0) {
if(ssl_ignore_mac_failed) {
ssl_debug_printf("ssl_decrypt_record: mac failed, but ignored for troubleshooting ;-)\n");
}
ssl->session.version==DTLSV1DOT2_VERSION ||
ssl->session.version==DTLSV1DOT0_OPENSSL_VERSION){
/* Try rfc-compliant mac first, and if failed, try old openssl's non-rfc-compliant mac */
- if(dtls_check_mac(decoder,ct,ssl->session.version,out_str->data,worklen,mac)>= 0) {
+ if(dtls_check_mac(decoder,ct,ssl->session.version,mac_frag,mac_fraglen,mac)>= 0) {
ssl_debug_printf("ssl_decrypt_record: mac ok\n");
}
- else if(tls_check_mac(decoder,ct,TLSV1_VERSION,out_str->data,worklen,mac)>= 0) {
+ else if(tls_check_mac(decoder,ct,TLSV1_VERSION,mac_frag,mac_fraglen,mac)>= 0) {
ssl_debug_printf("ssl_decrypt_record: dtls rfc-compliant mac failed, but old openssl's non-rfc-compliant mac ok\n");
}
else if(ssl_ignore_mac_failed) {
/* Record decryption glue based on security parameters }}} */
-#if defined(HAVE_LIBGNUTLS)
-/* RSA private key file processing {{{ */
-#define RSA_PARS 6
-static gcry_sexp_t
-ssl_privkey_to_sexp(gnutls_x509_privkey_t priv_key)
-{
- gnutls_datum_t rsa_datum[RSA_PARS]; /* m, e, d, p, q, u */
- size_t tmp_size;
- gcry_error_t gret;
- gcry_sexp_t rsa_priv_key = NULL;
- gint i;
- gcry_mpi_t rsa_params[RSA_PARS];
-
- /* RSA get parameter */
- if (gnutls_x509_privkey_export_rsa_raw(priv_key,
- &rsa_datum[0],
- &rsa_datum[1],
- &rsa_datum[2],
- &rsa_datum[3],
- &rsa_datum[4],
- &rsa_datum[5]) != 0) {
- ssl_debug_printf("ssl_load_key: can't export rsa param (is a rsa private key file ?!?)\n");
- return NULL;
- }
-
- /* convert each rsa parameter to mpi format*/
- for(i=0; i<RSA_PARS; i++) {
- gret = gcry_mpi_scan(&rsa_params[i], GCRYMPI_FMT_USG, rsa_datum[i].data, rsa_datum[i].size,&tmp_size);
- /* these buffers were allocated by gnutls_x509_privkey_export_rsa_raw() */
- g_free(rsa_datum[i].data);
- if (gret != 0) {
- ssl_debug_printf("ssl_load_key: can't convert m rsa param to int (size %d)\n", rsa_datum[i].size);
- return NULL;
- }
- }
-
- /* libgcrypt expects p < q, and gnutls might not return it as such, depending on gnutls version and its crypto backend */
- if (gcry_mpi_cmp(rsa_params[3], rsa_params[4]) > 0)
- {
- ssl_debug_printf("ssl_load_key: swapping p and q parameters and recomputing u\n");
- /* p, q = q, p */
- gcry_mpi_swap(rsa_params[3], rsa_params[4]);
- /* due to swapping p and q, u = p^-1 mod p which happens to be needed. */
- }
- /* libgcrypt expects u = p^-1 mod q (for OpenPGP), but the u parameter
- * says u = q^-1 mod p. Recompute u = p^-1 mod q. Do this unconditionally as
- * at least GnuTLS 2.12.23 computes an invalid value. */
- gcry_mpi_invm(rsa_params[5], rsa_params[3], rsa_params[4]);
-
- if (gcry_sexp_build( &rsa_priv_key, NULL,
- "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))", rsa_params[0],
- rsa_params[1], rsa_params[2], rsa_params[3], rsa_params[4],
- rsa_params[5]) != 0) {
- ssl_debug_printf("ssl_load_key: can't build rsa private key s-exp\n");
- return NULL;
- }
-
- for (i=0; i< 6; i++)
- gcry_mpi_release(rsa_params[i]);
- return rsa_priv_key;
-}
-
-/** Load an RSA private key from specified file
- @param fp the file that contain the key data
- @return a pointer to the loaded key on success, or NULL */
-static gnutls_x509_privkey_t
-ssl_load_key(FILE* fp)
-{
- /* gnutls makes our work much harder, since we have to work internally with
- * s-exp formatted data, but PEM loader exports only in "gnutls_datum_t"
- * format, and a datum -> s-exp convertion function does not exist.
- */
- gnutls_x509_privkey_t priv_key;
- gnutls_datum_t key;
- ws_statb64 statbuf;
- gint ret;
- guint bytes;
-
- if (ws_fstat64(ws_fileno(fp), &statbuf) == -1) {
- ssl_debug_printf("ssl_load_key: can't ws_fstat64 file\n");
- return NULL;
- }
- if (S_ISDIR(statbuf.st_mode)) {
- ssl_debug_printf("ssl_load_key: file is a directory\n");
- errno = EISDIR;
- return NULL;
- }
- if (S_ISFIFO(statbuf.st_mode)) {
- ssl_debug_printf("ssl_load_key: file is a named pipe\n");
- errno = EINVAL;
- return NULL;
- }
- if (!S_ISREG(statbuf.st_mode)) {
- ssl_debug_printf("ssl_load_key: file is not a regular file\n");
- errno = EINVAL;
- return NULL;
- }
- /* XXX - check for a too-big size */
- /* load all file contents into a datum buffer*/
- key.data = (unsigned char *)g_malloc((size_t)statbuf.st_size);
- key.size = (int)statbuf.st_size;
- bytes = (guint) fread(key.data, 1, key.size, fp);
- if (bytes < key.size) {
- ssl_debug_printf("ssl_load_key: can't read from file %d bytes, got %d\n",
- key.size, bytes);
- g_free(key.data);
- return NULL;
- }
-
- /* init private key data*/
- gnutls_x509_privkey_init(&priv_key);
-
- /* import PEM data*/
- if ((ret = gnutls_x509_privkey_import(priv_key, &key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) {
- ssl_debug_printf("ssl_load_key: can't import pem data: %s\n", gnutls_strerror(ret));
- g_free(key.data);
- return NULL;
- }
-
- if (gnutls_x509_privkey_get_pk_algorithm(priv_key) != GNUTLS_PK_RSA) {
- ssl_debug_printf("ssl_load_key: private key public key algorithm isn't RSA\n");
- g_free(key.data);
- return NULL;
- }
-
- g_free(key.data);
-
- return priv_key;
-}
-
-static const char *
-BAGTYPE(gnutls_pkcs12_bag_type_t x) {
- switch (x) {
- case GNUTLS_BAG_EMPTY: return "Empty";
- case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: return "PKCS#8 Encrypted key";
- case GNUTLS_BAG_PKCS8_KEY: return "PKCS#8 Key";
- case GNUTLS_BAG_CERTIFICATE: return "Certificate";
- case GNUTLS_BAG_CRL: return "CRL";
- case GNUTLS_BAG_ENCRYPTED: return "Encrypted";
- case GNUTLS_BAG_UNKNOWN: return "Unknown";
- default: return "<undefined>";
- }
-}
-
-/**
- * Load a RSA private key from a PKCS#12 file.
- * @param fp the file that contains the key data.
- * @param cert_passwd password to decrypt the PKCS#12 file.
- * @param[out] err error message upon failure; NULL upon success.
- * @return a pointer to the loaded key on success; NULL upon failure.
- */
-static gnutls_x509_privkey_t
-ssl_load_pkcs12(FILE* fp, const gchar *cert_passwd, char** err) {
-
- int i, j, ret;
- int rest;
- unsigned char *p;
- gnutls_datum_t data;
- gnutls_pkcs12_bag_t bag = NULL;
- gnutls_pkcs12_bag_type_t bag_type;
- size_t len;
-
- gnutls_pkcs12_t ssl_p12 = NULL;
- gnutls_x509_privkey_t ssl_pkey = NULL;
-
- gnutls_x509_privkey_t priv_key = NULL;
- *err = NULL;
-
- rest = 4096;
- data.data = (unsigned char *)g_malloc(rest);
- data.size = rest;
- p = data.data;
- while ((len = fread(p, 1, rest, fp)) > 0) {
- p += len;
- rest -= (int) len;
- if (!rest) {
- rest = 1024;
- data.data = (unsigned char *)g_realloc(data.data, data.size + rest);
- p = data.data + data.size;
- data.size += rest;
- }
- }
- data.size -= rest;
- ssl_debug_printf("%d bytes read\n", data.size);
- if (!feof(fp)) {
- *err = g_strdup("Error during certificate reading.");
- ssl_debug_printf("%s\n", *err);
- g_free(data.data);
- return 0;
- }
-
- ret = gnutls_pkcs12_init(&ssl_p12);
- if (ret < 0) {
- *err = g_strdup_printf("gnutls_pkcs12_init(&st_p12) - %s", gnutls_strerror(ret));
- ssl_debug_printf("%s\n", *err);
- g_free(data.data);
- return 0;
- }
-
- /* load PKCS#12 in DER or PEM format */
- ret = gnutls_pkcs12_import(ssl_p12, &data, GNUTLS_X509_FMT_DER, 0);
- if (ret < 0) {
- *err = g_strdup_printf("could not load PKCS#12 in DER format: %s", gnutls_strerror(ret));
- ssl_debug_printf("%s\n", *err);
- g_free(*err);
-
- ret = gnutls_pkcs12_import(ssl_p12, &data, GNUTLS_X509_FMT_PEM, 0);
- if (ret < 0) {
- *err = g_strdup_printf("could not load PKCS#12 in PEM format: %s", gnutls_strerror(ret));
- ssl_debug_printf("%s\n", *err);
- } else {
- *err = NULL;
- }
- }
- g_free(data.data);
- if (ret < 0) {
- return 0;
- }
-
- ssl_debug_printf( "PKCS#12 imported\n");
-
- /* TODO: Use gnutls_pkcs12_simple_parse, since 3.1.0 (August 2012) */
- for (i=0; ; i++) {
-
- ret = gnutls_pkcs12_bag_init(&bag);
- if (ret < 0) break;
- ret = gnutls_pkcs12_get_bag(ssl_p12, i, bag);
- if (ret < 0) break;
-
- for (j=0; j<gnutls_pkcs12_bag_get_count(bag); j++) {
-
- ret = gnutls_pkcs12_bag_get_type(bag, j);
- if (ret < 0) goto done;
- bag_type = (gnutls_pkcs12_bag_type_t)ret;
- if (bag_type >= GNUTLS_BAG_UNKNOWN) goto done;
- ssl_debug_printf( "Bag %d/%d: %s\n", i, j, BAGTYPE(bag_type));
- if (bag_type == GNUTLS_BAG_ENCRYPTED) {
- ret = gnutls_pkcs12_bag_decrypt(bag, cert_passwd);
- if (ret == 0) {
- ret = gnutls_pkcs12_bag_get_type(bag, j);
- if (ret < 0) goto done;
- bag_type = (gnutls_pkcs12_bag_type_t)ret;
- if (bag_type >= GNUTLS_BAG_UNKNOWN) goto done;
- ssl_debug_printf( "Bag %d/%d decrypted: %s\n", i, j, BAGTYPE(bag_type));
- }
- }
-
- ret = gnutls_pkcs12_bag_get_data(bag, j, &data);
- if (ret < 0) goto done;
-
- switch (bag_type) {
-
- case GNUTLS_BAG_PKCS8_KEY:
- case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
-
- ret = gnutls_x509_privkey_init(&ssl_pkey);
- if (ret < 0) {
- *err = g_strdup_printf("gnutls_x509_privkey_init(&ssl_pkey) - %s", gnutls_strerror(ret));
- ssl_debug_printf("%s\n", *err);
- goto done;
- }
- ret = gnutls_x509_privkey_import_pkcs8(ssl_pkey, &data, GNUTLS_X509_FMT_DER, cert_passwd,
- (bag_type==GNUTLS_BAG_PKCS8_KEY) ? GNUTLS_PKCS_PLAIN : 0);
- if (ret < 0) {
- *err = g_strdup_printf("Can not decrypt private key - %s", gnutls_strerror(ret));
- ssl_debug_printf("%s\n", *err);
- goto done;
- }
-
- if (gnutls_x509_privkey_get_pk_algorithm(ssl_pkey) != GNUTLS_PK_RSA) {
- *err = g_strdup("ssl_load_pkcs12: private key public key algorithm isn't RSA");
- ssl_debug_printf("%s\n", *err);
- goto done;
- }
-
- /* Private key found, return it. */
- priv_key = ssl_pkey;
- goto done;
-
- default: ;
- }
- } /* j */
- if (bag) { gnutls_pkcs12_bag_deinit(bag); bag = NULL; }
- } /* i */
-
-done:
- if (!priv_key && ssl_pkey)
- gnutls_x509_privkey_deinit(ssl_pkey);
- if (bag)
- gnutls_pkcs12_bag_deinit(bag);
-
- return priv_key;
-}
-
-
-void
-ssl_private_key_free(gpointer key)
-{
- gcry_sexp_release((gcry_sexp_t) key);
-}
+#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 }}} */
-
-#else /* ! defined(HAVE_LIBGNUTLS) */
-void
-ssl_private_key_free(gpointer key _U_)
-{
-}
#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, 0);
+ pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto, curr_layer_num_ssl);
if (!pi)
{
pi = wmem_new0(wmem_file_scope(), SslPacketInfo);
- p_add_proto_data(wmem_file_scope(), pinfo, proto, 0, pi);
+ pi->srcport = pinfo->srcport;
+ pi->destport = pinfo->destport;
+ 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, 0);
+ pi = (SslPacketInfo *)p_get_proto_data(wmem_file_scope(), pinfo, proto, curr_layer_num_ssl);
if (!pi)
return NULL;
int ret;
size_t key_id_len = 20;
guchar *key_id = NULL;
+ char *err = NULL;
dissector_handle_t handle;
/* try to load keys file first */
fp = ws_fopen(uats->keyfile, "rb");
}
if ((gint)strlen(uats->password) == 0) {
- priv_key = ssl_load_key(fp);
+ priv_key = rsa_load_pem_key(fp, &err);
} else {
- char *err = NULL;
- priv_key = ssl_load_pkcs12(fp, uats->password, &err);
- if (err) {
- report_failure("%s\n", err);
- g_free(err);
- }
+ priv_key = rsa_load_pkcs12(fp, uats->password, &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);
}
ssl_print_data("KeyID", key_id, key_id_len);
- private_key = ssl_privkey_to_sexp(priv_key);
+ private_key = rsa_privkey_to_sexp(priv_key, &err);
if (!private_key) {
+ ssl_debug_printf("%s\n", err);
+ g_free(err);
report_failure("Can't extract private key parameters for %s", uats->keyfile);
goto end;
}
}
} /* }}} */
-/* 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);
- if (tls13_generate_keys(ssl, secret, is_from_server)) {
- /*
- * Remember the application traffic secret to support Key Update. The
- * other secrets cannot be used for this purpose, so free them.
- */
- SslDecoder *decoder = is_from_server ? ssl->server : ssl->client;
- StringInfo *app_secret = &decoder->app_traffic_secret;
- if (type == TLS_SECRET_APP) {
- app_secret->data = (guchar *) wmem_realloc(wmem_file_scope(),
- app_secret->data,
+ 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
+ * other secrets cannot be used for this purpose, so free them.
+ */
+ SslDecoder *decoder = is_from_server ? ssl->server : ssl->client;
+ StringInfo *app_secret = &decoder->app_traffic_secret;
+ if (type == TLS_SECRET_APP) {
+ app_secret->data = (guchar *) wmem_realloc(wmem_file_scope(),
+ app_secret->data,
secret->data_len);
ssl_data_set(app_secret, secret->data, secret->data_len);
} else {
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(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){
fp = ws_fopen(f->keyfile, "rb");
if (fp) {
char *msg = NULL;
- gnutls_x509_privkey_t priv_key = ssl_load_pkcs12(fp, p, &msg);
+ gnutls_x509_privkey_t priv_key = rsa_load_pkcs12(fp, p, &msg);
if (!priv_key) {
fclose(fp);
*err = g_strdup_printf("Could not load PKCS#12 key file: %s", msg);
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;
}
return offset;
} /* }}} */
+/* Dissection of DistinguishedName (for CertificateRequest and
+ * certificate_authorities extension). {{{ */
+static guint32
+tls_dissect_certificate_authorities(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, guint32 offset, guint32 offset_end)
+{
+ proto_item *ti;
+ proto_tree *subtree;
+ guint32 dnames_length, next_offset;
+ asn1_ctx_t asn1_ctx;
+
+
+ /* Note: minimum length is 0 for TLS 1.1/1.2 and 3 for earlier/later */
+ /* DistinguishedName certificate_authorities<0..2^16-1> */
+ if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &dnames_length,
+ hf->hf.hs_dnames_len, 0, G_MAXUINT16)) {
+ return offset_end;
+ }
+ offset += 2;
+ next_offset = offset + dnames_length;
+
+ if (dnames_length > 0) {
+ ti = proto_tree_add_none_format(tree,
+ hf->hf.hs_dnames,
+ tvb, offset, dnames_length,
+ "Distinguished Names (%d byte%s)",
+ dnames_length,
+ plurality(dnames_length, "", "s"));
+ subtree = proto_item_add_subtree(ti, hf->ett.dnames);
+
+ asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
+
+ while (offset < next_offset) {
+ /* get the length of the current certificate */
+ guint32 name_length;
+ /* opaque DistinguishedName<1..2^16-1> */
+ if (!ssl_add_vector(hf, tvb, pinfo, subtree, offset, next_offset, &name_length,
+ hf->hf.hs_dname_len, 1, G_MAXUINT16)) {
+ return next_offset;
+ }
+ offset += 2;
+
+ dissect_x509if_DistinguishedName(FALSE, tvb, offset, &asn1_ctx,
+ subtree, hf->hf.hs_dname);
+ offset += name_length;
+ }
+ }
+ return offset;
+} /* }}} */
+
+
/** TLS Extensions (in Client Hello and Server Hello). {{{ */
static gint
ssl_dissect_hnd_hello_ext_sig_hash_algs(ssl_common_dissect_t *hf, tvbuff_t *tvb,
proto_tree *tree, guint32 offset, guint32 offset_end,
guint8 hnd_type)
{
- /* https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.6
+ /* https://tools.ietf.org/html/draft-ietf-tls-tls13-19#section-4.2.8
* struct {
- * opaque identity<0..2^16-1>;
+ * opaque identity<1..2^16-1>;
* uint32 obfuscated_ticket_age;
* } PskIdentity;
* opaque PskBinderEntry<32..255>;
* struct {
* select (Handshake.msg_type) {
* case client_hello:
- * PskIdentity identities<6..2^16-1>;
+ * PskIdentity identities<7..2^16-1>;
* PskBinderEntry binders<33..2^16-1>;
* case server_hello:
* uint16 selected_identity;
case SSL_HND_CLIENT_HELLO: {
guint32 identities_length, identities_end, binders_length;
- /* PskIdentity identities<6..2^16-1> */
+ /* PskIdentity identities<7..2^16-1> */
if (!ssl_add_vector(hf, tvb, pinfo, psk_tree, offset, offset_end, &identities_length,
- hf->hf.hs_ext_psk_identities_length, 6, G_MAXUINT16)) {
+ hf->hf.hs_ext_psk_identities_length, 7, G_MAXUINT16)) {
return offset_end;
}
offset += 2;
identity_tree = proto_tree_add_subtree(psk_tree, tvb, offset, 4, hf->ett.hs_ext_psk_identity, NULL, "PSK Identity (");
- /* opaque identity<0..2^16-1> */
+ /* opaque identity<1..2^16-1> */
if (!ssl_add_vector(hf, tvb, pinfo, identity_tree, offset, identities_end, &identity_length,
- hf->hf.hs_ext_psk_identity_identity_length, 0, G_MAXUINT16)) {
+ hf->hf.hs_ext_psk_identity_identity_length, 1, G_MAXUINT16)) {
return identities_end;
}
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 tls_dissect_certificate_authorities(hf, tvb, pinfo, tree, offset, offset_end);
}
+static gint
+ssl_dissect_hnd_hello_ext_oid_filters(ssl_common_dissect_t *hf, tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, guint32 offset, guint32 offset_end)
+{
+ /* https://tools.ietf.org/html/draft-ietf-tls-tls13-19#section-4.3.2.1
+ * struct {
+ * opaque certificate_extension_oid<1..2^8-1>;
+ * opaque certificate_extension_values<0..2^16-1>;
+ * } OIDFilter;
+ * struct {
+ * OIDFilter filters<0..2^16-1>;
+ * } OIDFilterExtension;
+ */
+ proto_tree *subtree;
+ guint32 filters_length, oid_length, values_length, value_offset;
+ asn1_ctx_t asn1_ctx;
+ const char *oid, *name;
+
+ /* OIDFilter filters<0..2^16-1> */
+ if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &filters_length,
+ hf->hf.hs_ext_psk_ke_modes_length, 0, G_MAXUINT16)) {
+ return offset_end;
+ }
+ offset += 2;
+ offset_end = offset + filters_length;
+
+ asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
+
+ while (offset < offset_end) {
+ subtree = proto_tree_add_subtree(tree, tvb, offset, offset_end - offset,
+ hf->ett.hs_ext_oid_filter, NULL, "OID Filter");
+
+ /* opaque certificate_extension_oid<1..2^8-1> */
+ if (!ssl_add_vector(hf, tvb, pinfo, subtree, offset, offset_end, &oid_length,
+ hf->hf.hs_ext_oid_filters_oid_length, 1, G_MAXUINT8)) {
+ return offset_end;
+ }
+ offset++;
+ dissect_ber_object_identifier_str(FALSE, &asn1_ctx, subtree, tvb, offset,
+ hf->hf.hs_ext_oid_filters_oid, &oid);
+ offset += oid_length;
+
+ /* Append OID to tree label */
+ name = oid_resolved_from_string(wmem_packet_scope(), oid);
+ proto_item_append_text(subtree, " (%s)", name ? name : oid);
+
+ /* opaque certificate_extension_values<0..2^16-1> */
+ if (!ssl_add_vector(hf, tvb, pinfo, subtree, offset, offset_end, &values_length,
+ hf->hf.hs_ext_oid_filters_values_length, 0, G_MAXUINT16)) {
+ return offset_end;
+ }
+ offset += 2;
+ proto_item_set_len(subtree, 1 + oid_length + 2 + values_length);
+ if (values_length > 0) {
+ value_offset = offset;
+ value_offset = dissect_ber_identifier(pinfo, subtree, tvb, value_offset, NULL, NULL, NULL);
+ value_offset = dissect_ber_length(pinfo, subtree, tvb, value_offset, NULL, NULL);
+ call_ber_oid_callback(oid, tvb, value_offset, pinfo, subtree, NULL);
+ }
+ offset += values_length;
+ }
+
+ return offset;
+}
+
static gint
ssl_dissect_hnd_hello_ext_server_name(ssl_common_dissect_t *hf, tvbuff_t *tvb,
packet_info *pinfo, proto_tree *tree,
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;
- 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);
+ 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 (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);
case SSL_HND_CLIENT_HELLO:
case SSL_HND_SERVER_HELLO:
case SSL_HND_NEWSESSION_TICKET:
+ case SSL_HND_END_OF_EARLY_DATA:
case SSL_HND_HELLO_RETRY_REQUEST:
case SSL_HND_ENCRYPTED_EXTENSIONS:
case SSL_HND_CERTIFICATE:
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 */
- server_version = TLSV1DOT3_VERSION;
- }
- 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<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 */
proto_tree_add_item(subtree, hf->hf.hs_session_ticket_age_add,
tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
+
+ /* for TLS 1.3: ticket_nonce (coming with Draft 21)*/
+ if (draft_version == 0 || draft_version >= 21) {
+ 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, 0, 255)) {
+ return;
+ }
+ offset++;
+
+ proto_tree_add_item(subtree, hf->hf.hs_session_ticket_nonce, tvb, offset, ticket_nonce_len, ENC_NA);
+ offset += ticket_nonce_len;
+ }
+
}
/* opaque ticket<0..2^16-1> (with TLS 1.3 the minimum is 1) */
SslSession *session, SslDecryptSession *ssl,
gboolean is_dtls)
{
- /* https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.1.4
+ /* https://tools.ietf.org/html/draft-ietf-tls-tls13-19#section-4.1.4
* struct {
* ProtocolVersion server_version;
+ * 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);
+ guint32 version;
+ guint8 draft_version;
+
+ 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);
* };
* } Certificate;
*
- * draft-ietf-tls-tls13-18:
- * opaque ASN1Cert<1..2^24-1>;
- * struct {
- * ASN1Cert cert_data;
- * Extension extensions<0..2^16-1>;
- * } CertificateEntry;
- * struct {
- * opaque certificate_request_context<0..2^8-1>;
- * CertificateEntry certificate_list<0..2^24-1>;
- * } Certificate;
+ * draft-ietf-tls-tls13-20:
+ * struct {
+ * select(certificate_type){
+ * case RawPublicKey:
+ * // From RFC 7250 ASN.1_subjectPublicKeyInfo
+ * opaque ASN1_subjectPublicKeyInfo<1..2^24-1>;
+ *
+ * case X.509:
+ * opaque cert_data<1..2^24-1>;
+ * }
+ * Extension extensions<0..2^16-1>;
+ * } CertificateEntry;
+ * struct {
+ * opaque certificate_request_context<0..2^8-1>;
+ * CertificateEntry certificate_list<0..2^24-1>;
+ * } Certificate;
*/
enum { CERT_X509, CERT_RPK } cert_type;
asn1_ctx_t asn1_ctx;
#if defined(HAVE_LIBGNUTLS)
gnutls_datum_t subjectPublicKeyInfo = { NULL, 0 };
#endif
- guint32 next_offset;
+ guint32 next_offset, certificate_list_length, cert_length;
+ proto_tree *subtree = tree;
+ guint certificate_index = 0;
asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
asn1_ctx.private_data = &subjectPublicKeyInfo;
#endif
- switch (cert_type) {
- case CERT_RPK:
- {
- guint32 cert_length;
+ /* TLS 1.3: opaque certificate_request_context<0..2^8-1> */
+ if (session->version == TLSV1DOT3_VERSION) {
+ guint32 context_length;
+ if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &context_length,
+ hf->hf.hs_certificate_request_context_length, 0, G_MAXUINT8)) {
+ return;
+ }
+ offset++;
+ if (context_length > 0) {
+ proto_tree_add_item(tree, hf->hf.hs_certificate_request_context,
+ tvb, offset, context_length, ENC_NA);
+ offset += context_length;
+ }
+ }
+
+ if (session->version != TLSV1DOT3_VERSION && cert_type == CERT_RPK) {
+ /* For RPK before TLS 1.3, the single RPK is stored directly without
+ * another "certificate_list" field. */
+ certificate_list_length = offset_end - offset;
+ next_offset = offset_end;
+ } else {
+ /* CertificateEntry certificate_list<0..2^24-1> */
+ if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &certificate_list_length,
+ hf->hf.hs_certificates_len, 0, G_MAXUINT24)) {
+ return;
+ }
+ offset += 3; /* 24-bit length value */
+ next_offset = offset + certificate_list_length;
+ }
+
+ /* RawPublicKey must have one cert, but X.509 can have multiple. */
+ if (certificate_list_length > 0 && cert_type == CERT_X509) {
+ proto_item *ti;
+
+ ti = proto_tree_add_none_format(tree,
+ hf->hf.hs_certificates,
+ tvb, offset, certificate_list_length,
+ "Certificates (%u bytes)",
+ certificate_list_length);
+
+ /* make it a subtree */
+ subtree = proto_item_add_subtree(ti, hf->ett.certificates);
+ }
+
+ while (offset < next_offset) {
+ switch (cert_type) {
+ case CERT_RPK:
+ /* TODO add expert info if there is more than one RPK entry (certificate_index > 0) */
/* opaque ASN.1_subjectPublicKeyInfo<1..2^24-1> */
- if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &cert_length,
+ if (!ssl_add_vector(hf, tvb, pinfo, subtree, offset, next_offset, &cert_length,
hf->hf.hs_certificate_len, 1, G_MAXUINT24)) {
return;
}
offset += 3;
- dissect_x509af_SubjectPublicKeyInfo(FALSE, tvb, offset, &asn1_ctx, tree, hf->hf.hs_certificate);
-
+ dissect_x509af_SubjectPublicKeyInfo(FALSE, tvb, offset, &asn1_ctx, subtree, hf->hf.hs_certificate);
+ offset += cert_length;
break;
- }
- case CERT_X509:
- {
- guint32 certificate_list_length;
- proto_item *ti;
- proto_tree *subtree;
-
- /* TLS 1.3: opaque certificate_request_context<0..2^8-1> */
- if (session->version == TLSV1DOT3_VERSION) {
- guint32 context_length;
- if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &context_length,
- hf->hf.hs_certificate_request_context_length, 0, G_MAXUINT8)) {
- return;
- }
- offset++;
- if (context_length > 0) {
- proto_tree_add_item(tree, hf->hf.hs_certificate_request_context,
- tvb, offset, context_length, ENC_NA);
- offset += context_length;
- }
- }
-
- /* CertificateEntry certificate_list<0..2^24-1> */
- if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &certificate_list_length,
- hf->hf.hs_certificates_len, 0, G_MAXUINT24)) {
+ case CERT_X509:
+ /* opaque ASN1Cert<1..2^24-1> */
+ if (!ssl_add_vector(hf, tvb, pinfo, subtree, offset, next_offset, &cert_length,
+ hf->hf.hs_certificate_len, 1, G_MAXUINT24)) {
return;
}
- offset += 3; /* 24-bit length value */
- next_offset = offset + certificate_list_length;
-
- if (certificate_list_length > 0) {
- ti = proto_tree_add_none_format(tree,
- hf->hf.hs_certificates,
- tvb, offset, certificate_list_length,
- "Certificates (%u bytes)",
- certificate_list_length);
-
- /* make it a subtree */
- subtree = proto_item_add_subtree(ti, hf->ett.certificates);
-
- /* iterate through each certificate */
- while (offset < next_offset) {
- guint32 cert_length;
- /* opaque ASN1Cert<1..2^24-1> */
- if (!ssl_add_vector(hf, tvb, pinfo, subtree, offset, next_offset, &cert_length,
- hf->hf.hs_certificate_len, 1, G_MAXUINT24)) {
- return;
- }
- offset += 3;
-
- dissect_x509af_Certificate(FALSE, tvb, offset, &asn1_ctx, subtree, hf->hf.hs_certificate);
-#if defined(HAVE_LIBGNUTLS)
- /* Only attempt to get the RSA modulus for the first cert. */
- asn1_ctx.private_data = NULL;
-#endif
-
- offset += cert_length;
+ offset += 3;
- /* TLS 1.3: Extension extensions<0..2^16-1> */
- if (session->version == TLSV1DOT3_VERSION) {
- offset = ssl_dissect_hnd_extension(hf, tvb, subtree, pinfo, offset,
- next_offset, SSL_HND_CERTIFICATE,
- session, ssl, is_dtls);
- }
- }
+ dissect_x509af_Certificate(FALSE, tvb, offset, &asn1_ctx, subtree, hf->hf.hs_certificate);
+#if defined(HAVE_LIBGNUTLS)
+ if (is_from_server && ssl && certificate_index == 0) {
+ ssl_find_private_key_by_pubkey(ssl, key_hash, &subjectPublicKeyInfo);
+ /* Only attempt to get the RSA modulus for the first cert. */
+ asn1_ctx.private_data = NULL;
}
+#endif
+ offset += cert_length;
break;
}
- }
-#if defined(HAVE_LIBGNUTLS)
- if (is_from_server && ssl)
- ssl_find_private_key_by_pubkey(ssl, key_hash, &subjectPublicKeyInfo);
-#endif
+ /* TLS 1.3: Extension extensions<0..2^16-1> */
+ if (session->version == TLSV1DOT3_VERSION) {
+ offset = ssl_dissect_hnd_extension(hf, tvb, subtree, pinfo, offset,
+ next_offset, SSL_HND_CERTIFICATE,
+ session, ssl, is_dtls);
+ }
+
+ certificate_index++;
+ }
}
void
* DistinguishedName certificate_authorities<0..2^16-1>;
* } CertificateRequest;
*
- * draft-ietf-tls-tls13-18 (soon obsolete!):
- * Note: certificate_extensions is not dissected since it is removed in next
- * draft.
- *
+ * draft-ietf-tls-tls13-18:
* struct {
* opaque certificate_request_context<0..2^8-1>;
- * SignatureScheme supported_signature_algorithms<2..2^16-2>;
+ * 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 (between -18 and -19, 2017-01-30):
+ * draft-ietf-tls-tls13-19:
*
* struct {
* opaque certificate_request_context<0..2^8-1>;
*/
proto_item *ti;
proto_tree *subtree;
- guint32 dnames_length = 0, next_offset;
+ 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:
- case TLSV1DOT3_VERSION: /* XXX draft -18 only, remove for next version */
- offset = ssl_dissect_hash_alg_list(hf, tvb, tree, pinfo, offset, offset_end);
- break;
-
- default:
- break;
- }
-
- /* DistinguishedName certificate_authorities<0..2^16-1> */
- if (!ssl_add_vector(hf, tvb, pinfo, tree, offset, offset_end, &dnames_length,
- hf->hf.hs_dnames_len, 0, G_MAXUINT16)) {
- return;
- }
- offset += 2;
- next_offset = offset + dnames_length;
-
- if (dnames_length > 0) {
- ti = proto_tree_add_none_format(tree,
- hf->hf.hs_dnames,
- tvb, offset, dnames_length,
- "Distinguished Names (%d byte%s)",
- dnames_length,
- plurality(dnames_length, "", "s"));
- subtree = proto_item_add_subtree(ti, hf->ett.dnames);
-
- while (offset < next_offset) {
- /* get the length of the current certificate */
- guint32 name_length;
- /* opaque DistinguishedName<1..2^16-1> */
- if (!ssl_add_vector(hf, tvb, pinfo, subtree, offset, next_offset, &name_length,
- hf->hf.hs_dname_len, 1, G_MAXUINT16)) {
- return;
- }
- offset += 2;
-
- dissect_x509if_DistinguishedName(FALSE, tvb, offset, &asn1_ctx,
- subtree, hf->hf.hs_dname);
- offset += name_length;
- }
+ 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);
}
- /* TODO this is not valid for TLS 1.3 draft -18. When draft -19 is released, check if this is still correct. */
- 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);
}
}
/* Certificate and Certificate Request dissections. }}} */
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:
proto_tree_add_item(ext_tree, hf->hf.hs_ext_padding_data, tvb, offset, ext_len, ENC_NA);
offset += ext_len;
break;
+ case SSL_HND_HELLO_EXT_ENCRYPT_THEN_MAC:
+ if (ssl && hnd_type == SSL_HND_SERVER_HELLO) {
+ ssl_debug_printf("%s enabling Encrypt-then-MAC\n", G_STRFUNC);
+ ssl->state |= SSL_ENCRYPT_THEN_MAC;
+ }
+ break;
case SSL_HND_HELLO_EXT_EXTENDED_MASTER_SECRET:
if (ssl) {
switch (hnd_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);
case SSL_HND_HELLO_EXT_CERTIFICATE_AUTHORITIES:
offset = ssl_dissect_hnd_hello_ext_certificate_authorities(hf, tvb, pinfo, ext_tree, offset, next_offset);
break;
+ case SSL_HND_HELLO_EXT_OID_FILTERS:
+ offset = ssl_dissect_hnd_hello_ext_oid_filters(hf, tvb, pinfo, ext_tree, offset, next_offset);
+ break;
+ case SSL_HND_HELLO_EXT_POST_HANDSHAKE_AUTH:
+ break;
case SSL_HND_HELLO_EXT_NPN:
offset = ssl_dissect_hnd_hello_ext_npn(hf, tvb, pinfo, ext_tree, offset, next_offset);
break;
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;
"<CRAND> = The Client's random number from the ClientHello message\n"
"\n"
"(All fields are in hex notation)",
- &(options->keylog_filename));
+ &(options->keylog_filename), FALSE);
}
void
guint32 old_length = ssl_session->handshake_data.data_len;
ssl_debug_printf("Calculating hash with offset %d %d\n", offset, length);
ssl_session->handshake_data.data = (guchar *)wmem_realloc(wmem_file_scope(), ssl_session->handshake_data.data, old_length + length);
- tvb_memcpy(tvb, ssl_session->handshake_data.data + old_length, offset, length);
+ if (tvb) {
+ tvb_memcpy(tvb, ssl_session->handshake_data.data + old_length, offset, length);
+ } else {
+ memset(ssl_session->handshake_data.data + old_length, 0, length);
+ }
ssl_session->handshake_data.data_len += length;
}
}