#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>
/*
{ 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" },
{ 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" },
{ 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 */
{ 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" },
{ 0, NULL }
};
+/* RFC 6091 3.1 */
+const value_string tls_certificate_type[] = {
+ { 0, "X.509" },
+ { 1, "OpenPGP" },
+ { 0, NULL }
+};
+
const value_string tls_cert_status_type[] = {
{ SSL_HND_CERT_STATUS_TYPE_OCSP, "OCSP" },
{ 0, NULL }
str->data_len = len;
}
-#ifdef HAVE_LIBGNUTLS
+#if defined(HAVE_LIBGNUTLS) && defined(HAVE_LIBGCRYPT)
static gint ver_major, ver_minor, ver_patch;
/* guchar * ivp; */
gint ret;
/* gint i; */
- gcry_cipher_hd_t c;
+ /* gcry_cipher_hd_t c; */
ret=0;
- c=(gcry_cipher_hd_t)*cipher;
+ /*c=(gcry_cipher_hd_t)*cipher;*/
ssl_debug_printf("--------------------------------------------------------------------");
/*for(ivp=c->iv,i=0; i < iv_len; i++ )
key_block.data_len = needed;
key_block.data = g_malloc(needed);
- if (!key_block.data) {
- ssl_debug_printf("ssl_generate_keyring_material can't allocate key_block (len %d)\n", needed);
- return -1;
- }
ssl_debug_printf("ssl_generate_keyring_material sess key generation\n");
if (PRF(ssl_session,&ssl_session->master_secret,"key expansion",
&ssl_session->server_random,&ssl_session->client_random,
sscanf(str, "%d.%d.%d", &ver_major, &ver_minor, &ver_patch);
}
-#else /* HAVE_LIBGNUTLS */
+#else /* defined(HAVE_LIBGNUTLS) && defined(HAVE_LIBGCRYPT) */
/* no libgnutl: dummy operation to keep interface consistent*/
void
ssl_lib_init(void)
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 */
rec->plain_data.data = (guchar*)(rec + 1);
memcpy(rec->plain_data.data, data, data_len);
rec->plain_data.data_len = data_len;
- rec->seq = flow->byte_seq;
- rec->nxtseq = flow->byte_seq + data_len;
- rec->flow = flow;
+ if (flow)
+ {
+ rec->seq = flow->byte_seq;
+ rec->nxtseq = flow->byte_seq + data_len;
+ rec->flow = flow;
+ flow->byte_seq += data_len;
+ }
rec->next = NULL;
- flow->byte_seq += data_len;
-
/* insertion */
prec = &pi->appl_data;
while (*prec) prec = &(*prec)->next;
/* 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;
-
- 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;
-
- addr = start;
- /* split ip/file couple with ';' separator*/
- end = strpbrk(start, ";\n\r");
- if (end) {
- *end = 0;
- start = end+1;
- }
-
- /* skip comments (in file) */
- if (addr[0] == '#') continue;
-
- /* 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++;
+ FILE* fp = NULL;
+ guint32 addr_data[4];
+ int addr_len, at;
+ address_type addr_type[2] = { AT_IPv4, AT_IPv6 };
+
+ /* 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;
+ }
- protocol = strchr(port,',');
- if (!protocol)
- {
- ssl_debug_printf("ssl_init entry malformed can't find protocol in %s\n", port);
- continue;
- }
- *protocol=0;
- protocol++;
+ if ((gint)strlen(uats->password) == 0) {
+ private_key = ssl_load_key(fp);
+ } else {
+ private_key = ssl_load_pkcs12(fp, uats->password);
+ }
- filename = strchr(protocol,',');
- if (!filename)
- {
- ssl_debug_printf("ssl_init entry malformed can't find filename in %s\n", protocol);
- continue;
- }
- *filename=0;
- filename++;
+ if (!private_key) {
+ fprintf(stderr,"Can't load private key from %s\n", uats->keyfile);
+ return;
+ }
- cert_passwd = strchr(filename,',');
- if (cert_passwd)
- {
- *cert_passwd=0;
- cert_passwd++;
- }
+ fclose(fp);
- /* 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);
+ for (at = 0; at < 2; at++) {
+ memset(addr_data, 0, sizeof(addr_data));
+ addr_len = 0;
- /* remove all spaces in addr */
- read_index = 0;
- write_index = 0;
+ /* any: IPv4 or IPv6 wildcard */
+ /* anyipv4: IPv4 wildcard */
+ /* anyipv6: IPv6 wildcard */
- 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 (! addr_len) {
+ continue;
}
- if(!strcmp("start_tls", port)) {
+ 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;
- }
-
- 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);
- continue;
+ service->port = atoi(uats->port);
}
- fclose(fp);
+ 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);
- 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);
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);
+ g_hash_table_insert(key_hash, service, private_key);
- } while (end != NULL);
- g_free(tmp);
+ ssl_association_add(associations, handle, service->port, uats->protocol, tcp, TRUE);
+ }
}
/* store master secret into session data cache */
return 0;
}
+static guint8
+from_hex_char(gchar c) {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return 16;
+}
+
+int
+ssl_keylog_lookup(SslDecryptSession* ssl_session,
+ const gchar* ssl_keylog_filename,
+ StringInfo* encrypted_pre_master) {
+ static const unsigned int kRSAPremasterLength = 48; /* RFC5246 7.4.7.1 */
+ FILE* ssl_keylog;
+ gsize bytes_read;
+ int ret = -1;
+
+ ssl_debug_printf("trying to use SSL keylog in %s\n", ssl_keylog_filename);
+
+ ssl_keylog = ws_fopen(ssl_keylog_filename, "r");
+ if (!ssl_keylog) {
+ ssl_debug_printf("failed to open SSL keylog\n");
+ return -1;
+ }
+
+ /* The format of the file is a series of records with one of the following formats:
+ * - "RSA xxxx yyyy"
+ * Where xxxx are the first 8 bytes of the encrypted pre-master secret (hex-encoded)
+ * Where yyyy is the cleartext pre-master secret (hex-encoded)
+ * (this is the original format introduced with bug 4349)
+ *
+ * - "RSA Sesion-ID:xxxx Master-Key:yyyy"
+ * Where xxxx is the SSL session ID (hex-encoded)
+ * Where yyyy is the cleartext master secret (hex-encoded)
+ * (added to support openssl s_client Master-Key output)
+ */
+ for (;;) {
+ char buf[512], *line;
+ unsigned int i;
+ unsigned int offset;
+
+ line = fgets(buf, sizeof(buf), ssl_keylog);
+ if (!line)
+ break;
+
+ bytes_read = strlen(line);
+ /* fgets includes the \n at the end of the line. */
+ if (bytes_read > 0) {
+ line[bytes_read - 1] = 0;
+ bytes_read--;
+ }
+
+ ssl_debug_printf(" checking keylog line: %s\n", line);
+
+ if ( memcmp(line, "RSA ", 4) != 0) {
+ ssl_debug_printf(" rejecting line due to bad format\n");
+ continue;
+ }
+
+ offset = 4;
+
+ if ( ssl_session->session_id.data_len>0 && memcmp(line+offset,"Session-ID:",11) == 0 ) {
+ offset += 11;
+ for (i = 0; i < ssl_session->session_id.data_len; i++) {
+ if (from_hex_char(line[offset + i*2]) != (ssl_session->session_id.data[i] >> 4) ||
+ from_hex_char(line[offset + i*2 + 1]) != (ssl_session->session_id.data[i] & 15)) {
+ line = NULL;
+ break;
+ }
+ }
+
+ if (line == NULL) {
+ ssl_debug_printf(" line does not match SSL-ID\n");
+ continue;
+ }
+
+ offset += 2*ssl_session->session_id.data_len;
+ offset++;
+
+ } else if( line[offset+16] == ' ' ) {
+ for (i = 0; i < 8; i++) {
+ if (from_hex_char(line[offset + i*2]) != (encrypted_pre_master->data[i] >> 4) ||
+ from_hex_char(line[offset + i*2 + 1]) != (encrypted_pre_master->data[i] & 15)) {
+ line = NULL;
+ break;
+ }
+ }
+
+ if (line == NULL) {
+ ssl_debug_printf(" line does not match encrypted pre-master secret\n");
+ continue;
+ }
+
+ offset += 17;
+
+ } else {
+ ssl_debug_printf(" rejecting line due to bad format\n");
+ continue;
+ }
+
+
+ /* This record seems to match. */
+ if (memcmp(line+offset, "Master-Key:", 11) == 0) {
+ /* Key is a MasterSecret */
+ offset += 11;
+ ssl_session->master_secret.data = se_alloc(kRSAPremasterLength);
+ for (i = 0; i < kRSAPremasterLength; i++) {
+ guint8 a = from_hex_char(line[offset + i*2]);
+ guint8 b = from_hex_char(line[offset + i*2 + 1]);
+ if (a == 16 || b == 16) {
+ line = NULL;
+ break;
+ }
+ ssl_session->master_secret.data[i] = a << 4 | b;
+ }
+
+ if (line == NULL) {
+ ssl_debug_printf(" line contains non-hex chars in master secret\n");
+ continue;
+ }
+
+ ssl_session->master_secret.data_len = kRSAPremasterLength;
+ ssl_session->state &= ~(SSL_PRE_MASTER_SECRET|SSL_HAVE_SESSION_KEY);
+ ssl_session->state |= SSL_MASTER_SECRET;
+ ssl_debug_printf("found master secret in key log\n");
+ ret = 0;
+ break;
+
+ } else {
+ /* Key is a PreMasterSecret */
+ ssl_session->pre_master_secret.data = se_alloc(kRSAPremasterLength);
+ for (i = 0; i < kRSAPremasterLength; i++) {
+ guint8 a = from_hex_char(line[offset + i*2]);
+ guint8 b = from_hex_char(line[offset + i*2 + 1]);
+ if (a == 16 || b == 16) {
+ line = NULL;
+ break;
+ }
+ ssl_session->pre_master_secret.data[i] = a << 4 | b;
+ }
+
+ if (line == NULL) {
+ ssl_debug_printf(" line contains non-hex chars in pre-master secret\n");
+ continue;
+ }
+
+ ssl_session->pre_master_secret.data_len = kRSAPremasterLength;
+ ssl_session->state &= ~(SSL_MASTER_SECRET|SSL_HAVE_SESSION_KEY);
+ ssl_session->state |= SSL_PRE_MASTER_SECRET;
+ ssl_debug_printf("found pre-master secret in key log\n");
+ ret = 0;
+ break;
+ }
+ }
+
+ fclose(ssl_keylog);
+ return ret;
+}
+
#ifdef SSL_DECRYPT_DEBUG
static FILE* ssl_debug_file=NULL;
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:
+ */