Have the time field in the Graph Analyzis windos use the same time format as used...
[metze/wireshark/wip.git] / gtk / export_sslkeys.c
1 /* export_sslkeys.c
2  *
3  * $Id$
4  *
5  * Export SSL Session Keys dialog
6  * by Sake Blok <sake@euronet.nl> (20110526)
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  *
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <ctype.h>
34
35 #ifdef HAVE_FCNTL_H
36 #include <fcntl.h>
37 #endif
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #include <gtk/gtk.h>
44 #include <gdk/gdkkeysyms.h>
45 #if GTK_CHECK_VERSION(3,0,0)
46 # include <gdk/gdkkeysyms-compat.h>
47 #endif
48 #include <wsutil/file_util.h>
49
50 #include <string.h>
51
52
53 #include <epan/filesystem.h>
54 #include <epan/packet.h>
55 #include <epan/epan_dissect.h>
56 #include <epan/charsets.h>
57 #include <epan/prefs.h>
58 #include <epan/dissectors/packet-ssl.h>
59 #include <epan/dissectors/packet-ssl-utils.h>
60
61 #include "../simple_dialog.h"
62 #include "../isprint.h"
63 #include "../alert_box.h"
64 #include "../progress_dlg.h"
65 #include "../ui_util.h"
66
67 #include "gtk/keys.h"
68 #include "gtk/color_utils.h"
69 #include "gtk/capture_file_dlg.h"
70 #include "gtk/packet_win.h"
71 #include "gtk/file_dlg.h"
72 #include "gtk/gui_utils.h"
73 #include "gtk/gtkglobals.h"
74 #include "gtk/font_utils.h"
75 #include "gtk/webbrowser.h"
76 #include "gtk/main.h"
77 #include "gtk/menus.h"
78 #include "gtk/recent.h"
79 #include "gtk/export_sslkeys.h"
80
81 #ifdef _WIN32
82 #include <gdk/gdkwin32.h>
83 #include <windows.h>
84 #include "win32/file_dlg_win32.h"
85 #endif
86
87 static void
88 ssl_export_sessions_func(gpointer key, gpointer value, gpointer user_data)
89 {
90     guint i;
91     size_t offset;
92     StringInfo* sslid = (StringInfo*)key;
93     StringInfo* mastersecret = (StringInfo*)value;
94     StringInfo* keylist = (StringInfo*)user_data;
95
96     offset = strlen(keylist->data);
97
98     /*
99      * XXX - should this be a string that grows as necessary to hold
100      * everything in it?
101      */
102     g_snprintf(keylist->data+offset,(gulong)(keylist->data_len-offset),"RSA Session-ID:");
103     offset += 15;
104
105     for( i=0; i<sslid->data_len; i++) {
106         g_snprintf(keylist->data+offset,(gulong)(keylist->data_len-offset),"%.2x",sslid->data[i]&255);
107         offset += 2;
108     }
109
110     g_snprintf(keylist->data+offset,(gulong)(keylist->data_len-offset)," Master-Key:");
111     offset += 12;
112
113     for( i=0; i<mastersecret->data_len; i++) {
114         g_snprintf(keylist->data+offset,(gulong)(keylist->data_len-offset),"%.2x",mastersecret->data[i]&255);
115         offset += 2;
116     }
117
118     g_snprintf(keylist->data+offset,(gulong)(keylist->data_len-offset),"\n");
119 }
120
121 StringInfo*
122 ssl_export_sessions(GHashTable *session_hash)
123 {
124     StringInfo* keylist;
125
126     /* Output format is:
127      * "RSA Session-ID:xxxx Master-Key:yyyy\n"
128      * Where xxxx is the session ID in hex (max 64 chars)
129      * Where yyyy is the Master Key in hex (always 96 chars)
130      * So in total max 3+1+11+64+1+11+96+2 = 189 chars
131      */
132     keylist = g_malloc0(sizeof(StringInfo)+189*g_hash_table_size (session_hash));
133     keylist->data = ((guchar*)keylist+sizeof(StringInfo));
134     keylist->data_len = sizeof(StringInfo)+189*g_hash_table_size (session_hash);
135
136     g_hash_table_foreach(session_hash, ssl_export_sessions_func, (gpointer)keylist);
137
138     return keylist;
139 }
140 static GtkWidget *savesslkeys_dlg=NULL;
141
142 static void
143 savesslkeys_dlg_destroy_cb(GtkWidget *w _U_, gpointer user_data _U_)
144 {
145     savesslkeys_dlg = NULL;
146 }
147
148 /* save the SSL Session Keys */
149 static gboolean
150 savesslkeys_save_clicked_cb(GtkWidget * w _U_, gpointer data _U_)
151 {
152     int fd;
153     char *file;
154     StringInfo *keylist;
155
156     file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(savesslkeys_dlg));
157
158     if (test_for_directory(file) == EISDIR) {
159         /* It's a directory - set the file selection box to display that
160            directory, and leave the selection box displayed. */
161         set_last_open_dir(file);
162         g_free(file);
163         file_selection_set_current_folder(savesslkeys_dlg, get_last_open_dir());
164         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(savesslkeys_dlg), "");
165         return FALSE; /* do gtk_dialog_run again */
166     }
167
168     /* XXX: Must check if file name exists first */
169
170     /*
171      * Retrieve the info we need
172      */
173     keylist = ssl_export_sessions(ssl_session_hash);
174
175     if (keylist->data_len == 0 ) {
176         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
177                       "No SSL Session Keys to export!");
178         g_free(keylist);
179         g_free(file);
180         return TRUE;
181     }
182
183     fd = ws_open(file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
184     if (fd == -1) {
185         open_failure_alert_box(file, errno, TRUE);
186         g_free(keylist);
187         g_free(file);
188         return TRUE;
189     }
190     /*
191      * Thanks, Microsoft, for not using size_t for the third argument to
192      * _write().  Presumably this string will be <= 4GiB long....
193      */
194     if (ws_write(fd, keylist->data, (unsigned int)strlen(keylist->data)) < 0) {
195         write_failure_alert_box(file, errno);
196         ws_close(fd);
197         g_free(keylist);
198         g_free(file);
199         return TRUE;
200     }
201     if (ws_close(fd) < 0) {
202         write_failure_alert_box(file, errno);
203         g_free(keylist);
204         g_free(file);
205         return TRUE;
206     }
207
208     /* Get rid of the dialog box */
209     g_free(keylist);
210     g_free(file);
211     return TRUE;
212 }
213
214
215 /* Launch the dialog box to put up the file selection box etc */
216 #ifdef _WIN32
217 void
218 savesslkeys_cb(GtkWidget * w _U_, gpointer data _U_)
219 {
220     win32_export_sslkeys_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
221     return;
222 }
223 #else
224 void
225 savesslkeys_cb(GtkWidget * w _U_, gpointer data _U_)
226 {
227     gchar *label;
228     GtkWidget   *dlg_lb;
229     guint keylist_len;
230
231     keylist_len = g_hash_table_size(ssl_session_hash);
232     /* don't show up the dialog, if no data has to be saved */
233     if (keylist_len==0) {
234         /* shouldn't happen as the menu item should have been greyed out */
235         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "There are no SSL Session Keys to save!");
236         return;
237     }
238
239
240     /*
241      * Build the dialog box we need.
242      */
243     savesslkeys_dlg = file_selection_new("Wireshark: Export SSL Session Keys", FILE_SELECTION_SAVE);
244     gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(savesslkeys_dlg), TRUE);
245
246     /* label */
247     label = g_strdup_printf("Will save %u SSL Session %s to specified file.",
248                             keylist_len, plurality(keylist_len, "key", "keys"));
249     dlg_lb = gtk_label_new(label);
250     g_free(label);
251     file_selection_set_extra_widget(savesslkeys_dlg, dlg_lb);
252     gtk_widget_show(dlg_lb);
253
254     g_signal_connect(savesslkeys_dlg, "destroy", G_CALLBACK(savesslkeys_dlg_destroy_cb), NULL);
255
256     /* "Run" the GtkFileChooserDialog.                                              */
257     /* Upon exit: If "Accept" run the OK callback.                                  */
258     /*            If the OK callback returns with a FALSE status, re-run the dialog.*/
259     /*            If not accept (ie: cancel) destroy the window.                    */
260     /* XXX: If the OK callback pops up an alert box (eg: for an error) it *must*    */
261     /*      return with a TRUE status so that the dialog window will be destroyed.  */
262     /*      Trying to re-run the dialog after popping up an alert box will not work */
263     /*       since the user will not be able to dismiss the alert box.              */
264     /*      The (somewhat unfriendly) effect: the user must re-invoke the           */
265     /*      GtkFileChooserDialog whenever the OK callback pops up an alert box.     */
266     /*                                                                              */
267     /*      ToDo: use GtkFileChooserWidget in a dialog window instead of            */
268     /*            GtkFileChooserDialog.                                             */
269     while (gtk_dialog_run(GTK_DIALOG(savesslkeys_dlg)) == GTK_RESPONSE_ACCEPT) {
270         if (savesslkeys_save_clicked_cb(NULL, savesslkeys_dlg)) {
271             break; /* we're done */
272         }
273     }
274     window_destroy(savesslkeys_dlg);
275 }
276 #endif