From Ivan Sy via bug 3343:

- Support for DTLS and SSL RSA keys list using User Accessible Table
- Support for IPv6 SSL as posted by bug#3343 comment#1
- 'any' and 'anyipv4' for IPv4 wildcard
- 'anyipv6' for IPv6 wildcard
- UAT fields validation.


From me:

- Update paramaters to match UAT API changes.
- Change the UAT filename.
- Fix buffer overflow for IPv6 addresses.
- Allow the use of hostnames along with numeric addresses.
- Don't convert strings to addresses twice.
- Don't use the same variable name for different data types.
- Make "any" mean "any IPv4 or any IPv6".
- Bend the concept of obsolete preferences slightly so that we can convert
  and old-style key list to a UAT.
- Clean up whitespace.
- Don't point to a User's Guide section for now; it may make more sense to
  keep using the wiki page.
  
SSL dissector changes have been tested. DTLS dissector changes have not.

svn path=/trunk/; revision=36875
This commit is contained in:
Gerald Combs 2011-04-26 21:59:11 +00:00
parent 6eae60aa2f
commit c6fecb57b0
6 changed files with 541 additions and 203 deletions

View File

@ -74,6 +74,12 @@
#include "wsutil/inet_v6defs.h"
#endif
#include "packet-ssl-utils.h"
#include <wsutil/file_util.h>
#include <epan/uat.h>
/* DTLS User Access Table */
static ssldecrypt_assoc_t *dtlskeylist_uats = NULL;
static guint ndtlsdecrypt = 0;
/* we need to remember the top tree so that subdissectors we call are created
* at the root and not deep down inside the DTLS decode
@ -174,6 +180,7 @@ static StringInfo dtls_compressed_data = {NULL, 0};
static StringInfo dtls_decrypted_data = {NULL, 0};
static gint dtls_decrypted_data_avail = 0;
static uat_t *dtlsdecrypt_uat = NULL;
static gchar* dtls_keys_list = NULL;
#ifdef HAVE_LIBGNUTLS
static gchar* dtls_debug_file_name = NULL;
@ -204,8 +211,19 @@ static const fragment_items dtls_frag_items = {
static void
dtls_init(void)
{
module_t *dtls_module = prefs_find_module("dtls");
pref_t *keys_list_pref;
ssl_common_init(&dtls_session_hash, &dtls_decrypted_data, &dtls_compressed_data);
fragment_table_init (&dtls_fragment_table);
/* We should have loaded "keys_list" by now. Mark it obsolete */
if (dtls_module) {
keys_list_pref = prefs_find_preference(dtls_module, "keys_list");
if (! prefs_get_preference_obsolete(keys_list_pref)) {
prefs_set_preference_obsolete(keys_list_pref);
}
}
}
/* parse dtls related preferences (private keys and ports association strings) */
@ -214,6 +232,9 @@ dtls_parse(void)
{
ep_stack_t tmp_stack;
SslAssociation *tmp_assoc;
guint i;
gchar **old_keys, **parts, *err;
GString *uat_entry = g_string_new("");
if (dtls_key_hash)
{
@ -228,13 +249,37 @@ dtls_parse(void)
ssl_association_remove(dtls_associations, tmp_assoc);
}
/* Import old-style keys */
if (dtlsdecrypt_uat && dtls_keys_list && dtls_keys_list[0]) {
old_keys = g_strsplit(dtls_keys_list, ";", 0);
for (i = 0; old_keys[i] != NULL; i++) {
parts = g_strsplit(old_keys[i], ",", 4);
if (parts[0] && parts[1] && parts[2] && parts[3]) {
g_string_printf(uat_entry, "\"%s\",\"%s\",\"%s\",\"%s\",\"\"",
parts[0], parts[1], parts[2], parts[3]);
if (!uat_load_str(dtlsdecrypt_uat, uat_entry->str, &err)) {
ssl_debug_printf("dtls_parse: Can't load UAT string %s: %s\n",
uat_entry->str, err);
}
}
g_strfreev(parts);
}
g_strfreev(old_keys);
}
g_string_free(uat_entry, TRUE);
/* parse private keys string, load available keys and put them in key hash*/
dtls_key_hash = g_hash_table_new(ssl_private_key_hash, ssl_private_key_equal);
if (dtls_keys_list && (dtls_keys_list[0] != 0))
{
ssl_parse_key_list(dtls_keys_list,dtls_key_hash,dtls_associations,dtls_handle,FALSE);
}
if (ndtlsdecrypt > 0)
{
for (i = 0; i < ndtlsdecrypt; i++)
{
ssldecrypt_assoc_t *d = &(dtlskeylist_uats[i]);
ssl_parse_key_list(d, dtls_key_hash, dtls_associations, dtls_handle, FALSE);
}
}
ssl_set_debug(dtls_debug_file_name);
@ -1908,6 +1953,49 @@ looks_like_dtls(tvbuff_t *tvb, guint32 offset)
return 1;
}
/* UAT */
static void
dtlsdecrypt_free_cb(void* r)
{
ssldecrypt_assoc_t* h = r;
g_free(h->ipaddr);
g_free(h->port);
g_free(h->protocol);
g_free(h->keyfile);
g_free(h->password);
}
#if 0
static void
dtlsdecrypt_update_cb(void* r _U_, const char** err _U_)
{
return;
}
#endif
static void *
dtlsdecrypt_copy_cb(void* dest, const void* orig, size_t len _U_)
{
const ssldecrypt_assoc_t* o = orig;
ssldecrypt_assoc_t* d = dest;
d->ipaddr = g_strdup(o->ipaddr);
d->port = g_strdup(o->port);
d->protocol = g_strdup(o->protocol);
d->keyfile = g_strdup(o->keyfile);
d->password = g_strdup(o->password);
return d;
}
UAT_CSTRING_CB_DEF(sslkeylist_uats,ipaddr,ssldecrypt_assoc_t)
UAT_CSTRING_CB_DEF(sslkeylist_uats,port,ssldecrypt_assoc_t)
UAT_CSTRING_CB_DEF(sslkeylist_uats,protocol,ssldecrypt_assoc_t)
UAT_CSTRING_CB_DEF(sslkeylist_uats,keyfile,ssldecrypt_assoc_t)
UAT_CSTRING_CB_DEF(sslkeylist_uats,password,ssldecrypt_assoc_t)
/*********************************************************************
*
* Standard Wireshark Protocol Registration and housekeeping
@ -2236,15 +2324,45 @@ proto_register_dtls(void)
#ifdef HAVE_LIBGNUTLS
{
module_t *dtls_module = prefs_register_protocol(proto_dtls, dtls_parse);
prefs_register_string_preference(dtls_module, "keys_list", "RSA keys list",
"semicolon separated list of private RSA keys used for DTLS decryption; "
"each list entry must be in the form of <ip>,<port>,<protocol>,<key_file_name>"
"<key_file_name> is the local file name of the RSA private key used by the specified server\n",
(const gchar **)&dtls_keys_list);
prefs_register_string_preference(dtls_module, "debug_file", "DTLS debug file",
static uat_field_t dtlskeylist_uats_flds[] = {
UAT_FLD_CSTRING_OTHER(sslkeylist_uats, ipaddr, "IP address", ssldecrypt_uat_fld_ip_chk_cb, "IPv4 or IPv6 address"),
UAT_FLD_CSTRING_OTHER(sslkeylist_uats, port, "Port", ssldecrypt_uat_fld_port_chk_cb, "Port Number"),
UAT_FLD_CSTRING_OTHER(sslkeylist_uats, protocol, "Protocol", ssldecrypt_uat_fld_protocol_chk_cb, "Protocol"),
UAT_FLD_CSTRING_OTHER(sslkeylist_uats, keyfile, "Key File", ssldecrypt_uat_fld_fileopen_chk_cb, "Path to the keyfile."),
UAT_FLD_CSTRING_OTHER(sslkeylist_uats, password," Password (p12 file)", ssldecrypt_uat_fld_password_chk_cb, "Password"),
UAT_END_FIELDS
};
dtlsdecrypt_uat = uat_new("DTLS RSA Keylist",
sizeof(ssldecrypt_assoc_t),
"dtlsdecrypttablefile", /* filename */
TRUE, /* from_profile */
(void*) &dtlskeylist_uats, /* data_ptr */
&ndtlsdecrypt, /* numitems_ptr */
UAT_CAT_FFMT, /* category */
"ChK12ProtocolsSection", /* TODO, need revision - help */
dtlsdecrypt_copy_cb,
NULL, /* dtlsdecrypt_update_cb? */
dtlsdecrypt_free_cb,
NULL,
dtlskeylist_uats_flds);
prefs_register_uat_preference(dtls_module, "cfg",
"RSA keys list",
"A table of RSA keys for DTLS decryption",
dtlsdecrypt_uat);
prefs_register_string_preference(dtls_module, "debug_file", "DTLS debug file",
"redirect dtls debug to file name; leave empty to disable debug, "
"use \"" SSL_DEBUG_USE_STDERR "\" to redirect output to stderr\n",
(const gchar **)&dtls_debug_file_name);
prefs_register_string_preference(dtls_module, "keys_list", "RSA keys list (deprecated)",
"Semicolon-separated list of private RSA keys used for DTLS decryption. "
"Used by versions of Wireshark prior to 1.6",
(const gchar **)&dtls_keys_list);
}
#endif

View File

@ -30,13 +30,17 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_LIBZ
#include <zlib.h>
#endif
#include "packet-ssl-utils.h"
#include <epan/emem.h>
#include <epan/strutil.h>
#include <epan/addr_resolv.h>
#include <epan/ipv6-utils.h>
#include <wsutil/file_util.h>
/*
@ -166,7 +170,7 @@ static const value_string ssl_20_cipher_suites[] = {
{ 0x00006B, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256" },
{ 0x00006C, "TLS_DH_anon_WITH_AES_128_CBC_SHA256" },
{ 0x00006D, "TLS_DH_anon_WITH_AES_256_CBC_SHA256" },
/* 0x00,0x6E-83 Unassigned */
/* 0x00,0x6E-83 Unassigned */
{ 0x000084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA" },
{ 0x000085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA" },
{ 0x000086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA" },
@ -238,9 +242,9 @@ static const value_string ssl_20_cipher_suites[] = {
{ 0x0000C3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256" },
{ 0x0000C4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256" },
{ 0x0000C5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256" },
/* 0x00,0xC6-FE Unassigned */
{ 0x0000FF, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" },
/* 0x01-BF,* Unassigned */
/* 0x00,0xC6-FE Unassigned */
{ 0x0000FF, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" },
/* 0x01-BF,* Unassigned */
/* From RFC 4492 */
{ 0x00c001, "TLS_ECDH_ECDSA_WITH_NULL_SHA" },
{ 0x00c002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA" },
@ -304,12 +308,12 @@ static const value_string ssl_20_cipher_suites[] = {
{ 0x00C039, "TLS_ECDHE_PSK_WITH_NULL_SHA" },
{ 0x00C03A, "TLS_ECDHE_PSK_WITH_NULL_SHA256" },
{ 0x00C03B, "TLS_ECDHE_PSK_WITH_NULL_SHA384" },
/* 0xC0,0x3C-FF Unassigned
0xC1-FD,* Unassigned
0xFE,0x00-FD Unassigned
0xFE,0xFE-FF Reserved to avoid conflicts with widely deployed implementations [Pasi_Eronen]
0xFF,0x00-FF Reserved for Private Use [RFC5246]
*/
/* 0xC0,0x3C-FF Unassigned
0xC1-FD,* Unassigned
0xFE,0x00-FD Unassigned
0xFE,0xFE-FF Reserved to avoid conflicts with widely deployed implementations [Pasi_Eronen]
0xFF,0x00-FF Reserved for Private Use [RFC5246]
*/
/* these from http://www.mozilla.org/projects/
security/pki/nss/ssl/fips-ssl-ciphersuites.html */
@ -709,10 +713,10 @@ static const value_string ssl_31_ciphersuite[] = {
{ 0x00C3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256" },
{ 0x00C4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256" },
{ 0x00C5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256" },
/* 0x00,0xC6-FE Unassigned */
/* 0x00,0xC6-FE Unassigned */
/* From RFC 5746 */
{ 0x0000FF, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" },
/* 0x01-BF,* Unassigned */
/* 0x01-BF,* Unassigned */
/* From RFC 4492 */
{ 0xc001, "TLS_ECDH_ECDSA_WITH_NULL_SHA" },
{ 0xc002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA" },
@ -2935,8 +2939,10 @@ ssl_private_key_hash (gconstpointer v)
void
ssl_private_key_free(gpointer id, gpointer key, gpointer dummy _U_)
{
g_free(id);
ssl_free_key((Ssl_private_key_t*) key);
if (id != NULL) {
g_free(id);
ssl_free_key((Ssl_private_key_t*) key);
}
}
/* handling of association between tls/dtls ports and clear text protocol */
@ -3147,137 +3153,76 @@ ssl_common_init(GHashTable **session_hash, StringInfo *decrypted_data, StringInf
/* parse ssl related preferences (private keys and ports association strings) */
void
ssl_parse_key_list(const gchar * keys_list, GHashTable *key_hash, GTree* associations, dissector_handle_t handle, gboolean tcp)
ssl_parse_key_list(const ssldecrypt_assoc_t * uats, GHashTable *key_hash, GTree* associations, dissector_handle_t handle, gboolean tcp)
{
gchar* end;
gchar* start;
gchar* tmp;
guchar* ip;
SslService* service;
Ssl_private_key_t * private_key, *tmp_private_key;
FILE* fp;
FILE* fp = NULL;
guint32 addr_data[4];
int addr_len, at;
address_type addr_type[2] = { AT_IPv4, AT_IPv6 };
start = g_strdup(keys_list);
tmp = start;
ssl_debug_printf("ssl_init keys string:\n%s\n", start);
do {
int read_index, write_index;
gchar* addr, *port, *protocol, *filename, *cert_passwd;
/* try to load keys file first */
fp = ws_fopen(uats->keyfile, "rb");
if (!fp) {
fprintf(stderr, "Can't open file %s\n",uats->keyfile);
return;
}
addr = start;
/* split ip/file couple with ';' separator*/
end = strpbrk(start, ";\n\r");
if (end) {
*end = 0;
start = end+1;
}
if ((gint)strlen(uats->password) == 0) {
private_key = ssl_load_key(fp);
} else {
private_key = ssl_load_pkcs12(fp, uats->password);
}
/* skip comments (in file) */
if (addr[0] == '#') continue;
if (!private_key) {
fprintf(stderr,"Can't load private key from %s\n", uats->keyfile);
return;
}
/* for each entry split ip, port, protocol, filename with ',' separator */
ssl_debug_printf("ssl_init found host entry %s\n", addr);
port = strchr(addr, ',');
if (!port)
{
ssl_debug_printf("ssl_init entry malformed can't find port in '%s'\n", addr);
continue;
}
*port = 0;
port++;
fclose(fp);
protocol = strchr(port,',');
if (!protocol)
{
ssl_debug_printf("ssl_init entry malformed can't find protocol in %s\n", port);
continue;
}
*protocol=0;
protocol++;
for (at = 0; at < 2; at++) {
memset(addr_data, 0, sizeof(addr_data));
addr_len = 0;
filename = strchr(protocol,',');
if (!filename)
{
ssl_debug_printf("ssl_init entry malformed can't find filename in %s\n", protocol);
continue;
}
*filename=0;
filename++;
/* any: IPv4 or IPv6 wildcard */
/* anyipv4: IPv4 wildcard */
/* anyipv6: IPv6 wildcard */
cert_passwd = strchr(filename,',');
if (cert_passwd)
{
*cert_passwd=0;
cert_passwd++;
}
/* convert ip and port string to network rappresentation*/
service = g_malloc(sizeof(SslService) + 4);
service->addr.type = AT_IPv4;
service->addr.len = 4;
service->addr.data = ip = ((guchar*)service) + sizeof(SslService);
/* remove all spaces in addr */
read_index = 0;
write_index = 0;
while(addr[read_index]) {
if (addr[read_index] != ' ') {
addr[write_index] = addr[read_index];
write_index++;
if(addr_type[at] == AT_IPv4) {
if (strcmp(uats->ipaddr, "any") == 0 || strcmp(uats->ipaddr, "anyipv4") == 0 ||
get_host_ipaddr(uats->ipaddr, &addr_data[0])) {
addr_len = 4;
}
} else { /* AT_IPv6 */
if(strcmp(uats->ipaddr, "any") == 0 || strcmp(uats->ipaddr, "anyipv6") == 0 ||
get_host_ipaddr6(uats->ipaddr, (struct e_in6_addr *) addr_data)) {
addr_len = 16;
}
read_index++;
}
addr[write_index] = 0;
if ( !strcmp("any", addr) || !strcmp("ANY", addr) ) {
ip[0] = 0;
ip[1] = 0;
ip[2] = 0;
ip[3] = 0;
} else {
guint tmp0, tmp1, tmp2, tmp3;
sscanf(addr, "%u.%u.%u.%u", &tmp0, &tmp1, &tmp2, &tmp3);
ip[0] = (guchar)tmp0;
ip[1] = (guchar)tmp1;
ip[2] = (guchar)tmp2;
ip[3] = (guchar)tmp3;
}
if(!strcmp("start_tls", port)) {
if (! addr_len) {
continue;
}
service = g_malloc(sizeof(SslService) + addr_len);
service->addr.type = addr_type[at];
service->addr.len = addr_len;
service->addr.data = ((guchar*)service) + sizeof(SslService);
memcpy((void*)service->addr.data, addr_data, addr_len);
if(strcmp(uats->port,"start_tls")==0) {
service->port = 0;
} else {
service->port = atoi(port);
}
ssl_debug_printf("ssl_init addr '%u.%u.%u.%u' port '%d' filename '%s' password(only for p12 file) '%s'\n",
ip[0], ip[1], ip[2], ip[3], service->port, filename, cert_passwd ? cert_passwd : "(null)");
/* try to load pen or p12 file*/
fp = ws_fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "can't open file %s \n",filename);
continue;
service->port = atoi(uats->port);
}
if (!cert_passwd) {
private_key = ssl_load_key(fp);
}
else
{
private_key = ssl_load_pkcs12(fp,cert_passwd);
}
/* !!! */
if (!private_key) {
fprintf(stderr,"can't load private key from %s\n",
filename);
fclose(fp);
continue;
}
ssl_debug_printf("ssl_init %s addr '%s' (%s) port '%d' filename '%s' password(only for p12 file) '%s'\n",
(addr_type[at] == AT_IPv4) ? "IPv4" : "IPv6", uats->ipaddr, ep_address_to_str(&service->addr),
service->port, uats->keyfile, uats->password);
fclose(fp);
ssl_debug_printf("ssl_init private key file %s successfully loaded\n",filename);
ssl_debug_printf("ssl_init private key file %s successfully loaded.\n", uats->keyfile);
/* if item exists, remove first */
tmp_private_key = g_hash_table_lookup(key_hash, service);
@ -3285,12 +3230,11 @@ ssl_parse_key_list(const gchar * keys_list, GHashTable *key_hash, GTree* associa
g_hash_table_remove(key_hash, service);
ssl_free_key(tmp_private_key);
}
g_hash_table_insert(key_hash, service, private_key);
ssl_association_add(associations, handle, service->port, protocol, tcp, TRUE);
} while (end != NULL);
g_free(tmp);
ssl_association_add(associations, handle, service->port, uats->protocol, tcp, TRUE);
}
}
/* store master secret into session data cache */
@ -3423,3 +3367,114 @@ ssl_print_string(const gchar* name, const StringInfo* data)
ssl_print_data(name, data->data, data->data_len);
}
#endif /* SSL_DECRYPT_DEBUG */
/* checks for SSL and DTLS UAT key list fields */
gboolean
ssldecrypt_uat_fld_ip_chk_cb(void* r _U_, const char* p, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, const char** err)
{
if ((gint)strlen(p) == 0) {
*err = ep_strdup_printf("No IP address given.");
return FALSE;
}
*err = NULL;
return TRUE;
}
gboolean
ssldecrypt_uat_fld_port_chk_cb(void* r _U_, const char* p, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, const char** err)
{
guint i;
if ((gint)strlen(p) == 0) {
*err = ep_strdup_printf("No Port given.");
return FALSE;
}
if (strcmp(p, "start_tls") != 0){
i = atoi(p);
if (i <= 0) {
*err = ep_strdup_printf("Invalid port given.");
return FALSE;
}
}
*err = NULL;
return TRUE;
}
gboolean
ssldecrypt_uat_fld_protocol_chk_cb(void* r _U_, const char* p, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, const char** err)
{
if ((gint)strlen(p) == 0) {
*err = ep_strdup_printf("No protocol given.");
return FALSE;
}
if (!find_dissector(p)) {
*err = ep_strdup_printf("Could not find dissector for: '%s'", p);
return FALSE;
}
*err = NULL;
return TRUE;
}
gboolean
ssldecrypt_uat_fld_fileopen_chk_cb(void* r _U_, const char* p, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, const char** err)
{
ws_statb64 st;
if ((gint)strlen(p) == 0) {
*err = ep_strdup_printf("No filename given.");
return FALSE;
} else {
if (ws_stat64(p, &st) != 0) {
*err = ep_strdup_printf("File '%s' does not exist or access is denied.", p);
return FALSE;
}
}
*err = NULL;
return TRUE;
}
gboolean
ssldecrypt_uat_fld_password_chk_cb(void* r _U_, const char* p, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, const char** err)
{
ssldecrypt_assoc_t* f = r;
FILE *fp = NULL;
if ((gint)strlen(p) > 0) {
fp = ws_fopen(f->keyfile, "rb");
if (fp) {
if (!ssl_load_pkcs12(fp, p)) {
fclose(fp);
*err = ep_strdup_printf("Invalid. Password is necessary only if you use PKCS#12 key file.");
return FALSE;
}
fclose(fp);
} else {
*err = ep_strdup_printf("Leave this field blank if the keyfile is not PKCS#12.");
return FALSE;
}
}
*err = NULL;
return TRUE;
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -346,6 +346,21 @@ typedef struct _Ssl_private_key {
SSL_PRIVATE_KEY *sexp_pkey;
} Ssl_private_key_t;
/* User Access Table */
typedef struct _ssldecrypt_assoc_t {
char* ipaddr;
char* port;
char* protocol;
char* keyfile;
char* password;
} ssldecrypt_assoc_t;
gboolean ssldecrypt_uat_fld_ip_chk_cb(void*, const char*, unsigned, const void*, const void*, const char** err);
gboolean ssldecrypt_uat_fld_port_chk_cb(void*, const char*, unsigned, const void*, const void*, const char** err);
gboolean ssldecrypt_uat_fld_protocol_chk_cb(void*, const char*, unsigned, const void*, const void*, const char** err);
gboolean ssldecrypt_uat_fld_fileopen_chk_cb(void*, const char*, unsigned, const void*, const void*, const char** err);
gboolean ssldecrypt_uat_fld_password_chk_cb(void*, const char*, unsigned, const void*, const void*, const char** err);
/** Initialize decryption engine/ssl layer. To be called once per execution */
extern void
ssl_lib_init(void);
@ -487,7 +502,7 @@ ssl_common_init(GHashTable **session_hash, StringInfo *decrypted_data, StringInf
/* parse ssl related preferences (private keys and ports association strings) */
extern void
ssl_parse_key_list(const gchar * keys_list, GHashTable *key_hash, GTree* associations, dissector_handle_t handle, gboolean tcp);
ssl_parse_key_list(const ssldecrypt_assoc_t * uats, GHashTable *key_hash, GTree* associations, dissector_handle_t handle, gboolean tcp);
/* store master secret into session data cache */
extern void
@ -525,6 +540,19 @@ ssl_debug_printf(const gchar* fmt _U_,...)
#define ssl_set_debug(name)
#define ssl_debug_flush()
#endif
#endif /* SSL_DECRYPT_DEBUG */
#endif
#endif /* SSL_UTILS_H */
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -129,7 +129,10 @@
#include "packet-ssl.h"
#include "packet-ssl-utils.h"
#include <wsutil/file_util.h>
#include <epan/uat.h>
static ssldecrypt_assoc_t *sslkeylist_uats = NULL;
static guint nssldecrypt = 0;
static gboolean ssl_desegment = TRUE;
static gboolean ssl_desegment_app_data = TRUE;
@ -294,6 +297,7 @@ static StringInfo ssl_compressed_data = {NULL, 0};
static StringInfo ssl_decrypted_data = {NULL, 0};
static gint ssl_decrypted_data_avail = 0;
static uat_t *ssldecrypt_uat = NULL;
static gchar* ssl_keys_list = NULL;
static gchar* ssl_psk = NULL;
@ -318,9 +322,20 @@ ssl_fragment_init(void)
static void
ssl_init(void)
{
module_t *ssl_module = prefs_find_module("ssl");
pref_t *keys_list_pref;
ssl_common_init(&ssl_session_hash, &ssl_decrypted_data, &ssl_compressed_data);
ssl_fragment_init();
ssl_debug_flush();
/* We should have loaded "keys_list" by now. Mark it obsolete */
if (ssl_module) {
keys_list_pref = prefs_find_preference(ssl_module, "keys_list");
if (! prefs_get_preference_obsolete(keys_list_pref)) {
prefs_set_preference_obsolete(keys_list_pref);
}
}
}
/* parse ssl related preferences (private keys and ports association strings) */
@ -329,12 +344,9 @@ ssl_parse(void)
{
ep_stack_t tmp_stack;
SslAssociation *tmp_assoc;
FILE *ssl_keys_file;
struct stat statb;
size_t size;
gchar *tmp_buf;
size_t nbytes;
gboolean read_failed;
guint i;
gchar **old_keys, **parts, *err;
GString *uat_entry = g_string_new("");
ssl_set_debug(ssl_debug_file_name);
@ -354,30 +366,32 @@ ssl_parse(void)
/* parse private keys string, load available keys and put them in key hash*/
ssl_key_hash = g_hash_table_new(ssl_private_key_hash,ssl_private_key_equal);
if (ssl_keys_list && (ssl_keys_list[0] != 0))
{
if (file_exists(ssl_keys_list)) {
if ((ssl_keys_file = ws_fopen(ssl_keys_list, "r"))) {
read_failed = FALSE;
fstat(fileno(ssl_keys_file), &statb);
size = (size_t)statb.st_size;
tmp_buf = ep_alloc0(size + 1);
nbytes = fread(tmp_buf, 1, size, ssl_keys_file);
if (ferror(ssl_keys_file)) {
report_read_failure(ssl_keys_list, errno);
read_failed = TRUE;
/* Import old-style keys */
if (ssldecrypt_uat && ssl_keys_list && ssl_keys_list[0]) {
old_keys = g_strsplit(ssl_keys_list, ";", 0);
for (i = 0; old_keys[i] != NULL; i++) {
parts = g_strsplit(old_keys[i], ",", 4);
if (parts[0] && parts[1] && parts[2] && parts[3]) {
g_string_printf(uat_entry, "\"%s\",\"%s\",\"%s\",\"%s\",\"\"",
parts[0], parts[1], parts[2], parts[3]);
if (!uat_load_str(ssldecrypt_uat, uat_entry->str, &err)) {
ssl_debug_printf("ssl_parse: Can't load UAT string %s: %s\n",
uat_entry->str, err);
}
fclose(ssl_keys_file);
tmp_buf[nbytes] = '\0';
if (!read_failed)
ssl_parse_key_list(tmp_buf,ssl_key_hash,ssl_associations,ssl_handle,TRUE);
} else {
report_open_failure(ssl_keys_list, errno, FALSE);
}
} else {
ssl_parse_key_list(ssl_keys_list,ssl_key_hash,ssl_associations,ssl_handle,TRUE);
g_strfreev(parts);
}
g_strfreev(old_keys);
}
g_string_free(uat_entry, TRUE);
if (nssldecrypt > 0) {
for (i = 0; i < nssldecrypt; i++) {
ssldecrypt_assoc_t *ssl_uat = &(sslkeylist_uats[i]);
ssl_parse_key_list(ssl_uat, ssl_key_hash, ssl_associations, ssl_handle, TRUE);
}
}
ssl_debug_flush();
}
@ -832,20 +846,20 @@ again:
* the pdu).
*/
if ((msp = se_tree_lookup32(flow->multisegment_pdus, seq))) {
const char* str;
const char* str;
if (msp->first_frame == PINFO_FD_NUM(pinfo)) {
str = "";
col_set_str(pinfo->cinfo, COL_INFO, "[SSL segment of a reassembled PDU]");
} else {
str = "Retransmitted ";
}
if (msp->first_frame == PINFO_FD_NUM(pinfo)) {
str = "";
col_set_str(pinfo->cinfo, COL_INFO, "[SSL segment of a reassembled PDU]");
} else {
str = "Retransmitted ";
}
nbytes = tvb_reported_length_remaining(tvb, offset);
proto_tree_add_text(tree, tvb, offset, nbytes,
"%sSSL segment data (%u byte%s)",
str, nbytes, plurality(nbytes, "", "s"));
return;
nbytes = tvb_reported_length_remaining(tvb, offset);
proto_tree_add_text(tree, tvb, offset, nbytes,
"%sSSL segment data (%u byte%s)",
str, nbytes, plurality(nbytes, "", "s"));
return;
}
/* Else, find the most previous PDU starting before this sequence number */
@ -946,7 +960,7 @@ again:
/* create a new TVB structure for desegmented data */
next_tvb = tvb_new_child_real_data(tvb, ipfd_head->data,
ipfd_head->datalen,
ipfd_head->datalen);
ipfd_head->datalen);
/* add desegmented data to the data source list */
add_new_data_source(pinfo, next_tvb, "Reassembled SSL");
@ -1030,7 +1044,7 @@ again:
* a higher-level PDU, but the data at the
* end of this segment started a higher-level
* PDU but didn't complete it.
*
*
* If so, we have to create some structures
* in our table, but this is something we
* only do the first time we see this packet.
@ -1042,12 +1056,12 @@ again:
/* The stuff we couldn't dissect
* must have come from this segment,
* so it's all in "tvb".
*
*
* "pinfo->desegment_offset" is
* relative to the beginning of
* "next_tvb"; we want an offset
* relative to the beginning of "tvb".
*
*
* First, compute the offset relative
* to the *end* of "next_tvb" - i.e.,
* the number of bytes before the end
@ -1067,7 +1081,7 @@ again:
* is also the offset relative to
* the end of "tvb" of the byte at
* which we stopped.
*
*
* Convert that back into an offset
* relative to the beginninng of
* "tvb", by taking the length of
@ -1104,19 +1118,19 @@ again:
if (((nxtseq - deseg_seq) <= 1024*1024)
&& (!PINFO_FD_VISITED(pinfo))) {
if(pinfo->desegment_len == DESEGMENT_ONE_MORE_SEGMENT) {
/* The subdissector asked to reassemble using the
if(pinfo->desegment_len == DESEGMENT_ONE_MORE_SEGMENT) {
/* The subdissector asked to reassemble using the
* entire next segment.
* Just ask reassembly for one more byte
* but set this msp flag so we can pick it up
* above.
*/
msp = pdu_store_sequencenumber_of_next_pdu(pinfo,
deseg_seq, nxtseq+1, flow->multisegment_pdus);
msp = pdu_store_sequencenumber_of_next_pdu(pinfo,
deseg_seq, nxtseq+1, flow->multisegment_pdus);
msp->flags |= MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT;
} else {
msp = pdu_store_sequencenumber_of_next_pdu(pinfo,
deseg_seq, nxtseq+pinfo->desegment_len, flow->multisegment_pdus);
deseg_seq, nxtseq+pinfo->desegment_len, flow->multisegment_pdus);
}
/* add this segment as the first one for this new pdu */
@ -2828,7 +2842,7 @@ dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
* that will break reassembly.
*/
pinfo->desegment_offset = offset;
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
*need_desegmentation = TRUE;
return offset;
}
@ -4191,6 +4205,48 @@ ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb, const guint32 offset,
return ret;
}
/* UAT */
static void
ssldecrypt_free_cb(void* r)
{
ssldecrypt_assoc_t* h = r;
g_free(h->ipaddr);
g_free(h->port);
g_free(h->protocol);
g_free(h->keyfile);
g_free(h->password);
}
static void
ssldecrypt_update_cb(void* r _U_, const char** err)
{
if (err)
*err = NULL;
return;
}
static void*
ssldecrypt_copy_cb(void* dest, const void* orig, size_t len _U_)
{
const ssldecrypt_assoc_t* o = orig;
ssldecrypt_assoc_t* d = dest;
d->ipaddr = g_strdup(o->ipaddr);
d->port = g_strdup(o->port);
d->protocol = g_strdup(o->protocol);
d->keyfile = g_strdup(o->keyfile);
d->password = g_strdup(o->password);
return d;
}
UAT_CSTRING_CB_DEF(sslkeylist_uats,ipaddr,ssldecrypt_assoc_t)
UAT_CSTRING_CB_DEF(sslkeylist_uats,port,ssldecrypt_assoc_t)
UAT_CSTRING_CB_DEF(sslkeylist_uats,protocol,ssldecrypt_assoc_t)
UAT_CSTRING_CB_DEF(sslkeylist_uats,keyfile,ssldecrypt_assoc_t)
UAT_CSTRING_CB_DEF(sslkeylist_uats,password,ssldecrypt_assoc_t)
/*********************************************************************
*
@ -4723,6 +4779,48 @@ proto_register_ssl(void)
{
module_t *ssl_module = prefs_register_protocol(proto_ssl, proto_reg_handoff_ssl);
#ifdef HAVE_LIBGNUTLS
static uat_field_t sslkeylist_uats_flds[] = {
UAT_FLD_CSTRING_OTHER(sslkeylist_uats, ipaddr, "IP address", ssldecrypt_uat_fld_ip_chk_cb, "IPv4 or IPv6 address"),
UAT_FLD_CSTRING_OTHER(sslkeylist_uats, port, "Port", ssldecrypt_uat_fld_port_chk_cb, "Port Number"),
UAT_FLD_CSTRING_OTHER(sslkeylist_uats, protocol, "Protocol", ssldecrypt_uat_fld_protocol_chk_cb, "Protocol"),
UAT_FLD_CSTRING_OTHER(sslkeylist_uats, keyfile, "Key File", ssldecrypt_uat_fld_fileopen_chk_cb, "Private keyfile."),
UAT_FLD_CSTRING_OTHER(sslkeylist_uats, password,"Password", ssldecrypt_uat_fld_password_chk_cb, "Password (for PCKS#12 keyfile)"),
UAT_END_FIELDS
};
ssldecrypt_uat = uat_new("SSL Decrypt",
sizeof(ssldecrypt_assoc_t),
"ssl_keys", /* filename */
TRUE, /* from_profile */
(void*) &sslkeylist_uats, /* data_ptr */
&nssldecrypt, /* numitems_ptr */
UAT_CAT_FFMT, /* category */
NULL, /* Help section (currently a wiki page) */
ssldecrypt_copy_cb,
ssldecrypt_update_cb,
ssldecrypt_free_cb,
NULL,
sslkeylist_uats_flds);
prefs_register_uat_preference(ssl_module, "key_table",
"RSA keys list",
"A table of RSA keys for SSL decryption",
ssldecrypt_uat);
prefs_register_string_preference(ssl_module, "debug_file", "SSL debug file",
"Redirect SSL debug to file name; leave empty to disable debugging, "
"or use \"" SSL_DEBUG_USE_STDERR "\" to redirect output to stderr\n",
(const gchar **)&ssl_debug_file_name);
prefs_register_string_preference(ssl_module, "keys_list", "RSA keys list (deprecated)",
"Semicolon-separated list of private RSA keys used for SSL decryption. "
"Used by versions of Wireshark prior to 1.6",
(const gchar **)&ssl_keys_list);
#endif
prefs_register_bool_preference(ssl_module,
"desegment_ssl_records",
"Reassemble SSL records spanning multiple TCP segments",
@ -4735,22 +4833,13 @@ proto_register_ssl(void)
"Whether the SSL dissector should reassemble SSL Application Data spanning multiple SSL records. ",
&ssl_desegment_app_data);
#ifdef HAVE_LIBGNUTLS
prefs_register_string_preference(ssl_module, "keys_list", "RSA keys list",
"Semicolon-separated list of private RSA keys used for SSL decryption; "
"each list entry must be in the form of <ip>,<port>,<protocol>,<key_file_name>. "
"<key_file_name> is the local file name of the RSA private key used by the specified server "
"(or name of the file containing such a list)",
(const gchar **)&ssl_keys_list);
prefs_register_string_preference(ssl_module, "debug_file", "SSL debug file",
"Redirect SSL debug to file name; leave empty to disable debugging, "
"or use \"" SSL_DEBUG_USE_STDERR "\" to redirect output to stderr\n",
(const gchar **)&ssl_debug_file_name);
prefs_register_string_preference(ssl_module, "psk", "Pre-Shared-Key",
"Pre-Shared-Key as HEX string, should be 0 to 16 bytes",
(const gchar **)&ssl_psk);
#endif
}
register_dissector("ssl", dissect_ssl, proto_ssl);
ssl_handle = find_dissector("ssl");
@ -4798,3 +4887,16 @@ ssl_dissector_delete(guint port, const gchar *protocol, gboolean tcp)
ssl_association_remove(ssl_associations, assoc);
}
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -828,6 +828,31 @@ prefs_register_obsolete_preference(module_t *module, const char *name)
register_preference(module, name, NULL, NULL, PREF_OBSOLETE);
}
/*
* Check to see if a preference is obsolete.
*/
extern gboolean
prefs_get_preference_obsolete(pref_t *pref)
{
if (pref) {
return pref->type == PREF_OBSOLETE ? TRUE : FALSE;
}
return TRUE;
}
/*
* Make a preference obsolete.
*/
extern prefs_set_pref_e
prefs_set_preference_obsolete(pref_t *pref)
{
if (pref) {
pref->type = PREF_OBSOLETE;
return PREFS_SET_OK;
}
return PREFS_SET_NO_SUCH_PREF;
}
/*
* Call a callback function, with a specified argument, for each preference
* in a given module.

View File

@ -373,6 +373,7 @@ extern void prefs_register_uat_preference(module_t *module,
extern void prefs_register_obsolete_preference(module_t *module,
const char *name);
typedef guint (*pref_cb)(pref_t *pref, gpointer user_data);
/*
@ -443,6 +444,15 @@ typedef enum {
extern prefs_set_pref_e prefs_set_pref(char *prefarg);
/*
* Get or set a preference's obsolete status. These can be used to make a
* preference obsolete after startup so that we can fetch its value but
* keep it from showing up in the prefrences dialog.
*/
extern gboolean prefs_get_preference_obsolete(pref_t *pref);
extern prefs_set_pref_e prefs_set_preference_obsolete(pref_t *pref);
/*
* Returns TRUE if the given device is hidden
*/