2006-01-13 [paul] 1.9.100cvs142
[claws.git] / src / gtk / sslcertwindow.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2006 Hiroyuki Yamamoto
4  * This file Copyright (C) 2002-2005 Colin Leroy <colin@colino.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #endif
24
25 #if USE_OPENSSL
26
27 #include <openssl/ssl.h>
28 #include <glib.h>
29 #include <glib/gi18n.h>
30 #include <gtk/gtk.h>
31
32 #include "ssl_certificate.h"
33 #include "utils.h"
34 #include "alertpanel.h"
35 #include "hooks.h"
36
37 gboolean sslcertwindow_ask_new_cert(SSLCertificate *cert);
38 gboolean sslcertwindow_ask_changed_cert(SSLCertificate *old_cert, SSLCertificate *new_cert);
39
40 GtkWidget *cert_presenter(SSLCertificate *cert)
41 {
42         GtkWidget *vbox = NULL;
43         GtkWidget *hbox = NULL;
44         GtkWidget *frame_owner = NULL;
45         GtkWidget *frame_signer = NULL;
46         GtkWidget *frame_status = NULL;
47         GtkTable *owner_table = NULL;
48         GtkTable *signer_table = NULL;
49         GtkTable *status_table = NULL;
50         GtkWidget *label = NULL;
51         char buf[100];
52         char *issuer_commonname, *issuer_location, *issuer_organization;
53         char *subject_commonname, *subject_location, *subject_organization;
54         char *fingerprint, *sig_status;
55         unsigned int n;
56         unsigned char md[EVP_MAX_MD_SIZE];      
57         
58         /* issuer */    
59         if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), 
60                                        NID_commonName, buf, 100) >= 0)
61                 issuer_commonname = g_strdup(buf);
62         else
63                 issuer_commonname = g_strdup(_("<not in certificate>"));
64         if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), 
65                                        NID_localityName, buf, 100) >= 0) {
66                 issuer_location = g_strdup(buf);
67                 if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), 
68                                        NID_countryName, buf, 100) >= 0)
69                         issuer_location = g_strconcat(issuer_location,", ",buf, NULL);
70         } else if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), 
71                                        NID_countryName, buf, 100) >= 0)
72                 issuer_location = g_strdup(buf);
73         else
74                 issuer_location = g_strdup(_("<not in certificate>"));
75
76         if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), 
77                                        NID_organizationName, buf, 100) >= 0)
78                 issuer_organization = g_strdup(buf);
79         else 
80                 issuer_organization = g_strdup(_("<not in certificate>"));
81          
82         /* subject */   
83         if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), 
84                                        NID_commonName, buf, 100) >= 0)
85                 subject_commonname = g_strdup(buf);
86         else
87                 subject_commonname = g_strdup(_("<not in certificate>"));
88         if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), 
89                                        NID_localityName, buf, 100) >= 0) {
90                 subject_location = g_strdup(buf);
91                 if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), 
92                                        NID_countryName, buf, 100) >= 0)
93                         subject_location = g_strconcat(subject_location,", ",buf, NULL);
94         } else if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), 
95                                        NID_countryName, buf, 100) >= 0)
96                 subject_location = g_strdup(buf);
97         else
98                 subject_location = g_strdup(_("<not in certificate>"));
99
100         if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), 
101                                        NID_organizationName, buf, 100) >= 0)
102                 subject_organization = g_strdup(buf);
103         else 
104                 subject_organization = g_strdup(_("<not in certificate>"));
105          
106         /* fingerprint */
107         X509_digest(cert->x509_cert, EVP_md5(), md, &n);
108         fingerprint = readable_fingerprint(md, (int)n);
109
110         /* signature */
111         sig_status = ssl_certificate_check_signer(cert->x509_cert);
112
113         if (sig_status==NULL)
114                 sig_status = g_strdup(_("correct"));
115
116         vbox = gtk_vbox_new(FALSE, 5);
117         hbox = gtk_hbox_new(FALSE, 5);
118         
119         frame_owner  = gtk_frame_new(_("Owner"));
120         frame_signer = gtk_frame_new(_("Signer"));
121         frame_status = gtk_frame_new(_("Status"));
122         
123         owner_table = GTK_TABLE(gtk_table_new(3, 2, FALSE));
124         signer_table = GTK_TABLE(gtk_table_new(3, 2, FALSE));
125         status_table = GTK_TABLE(gtk_table_new(2, 2, FALSE));
126         
127         label = gtk_label_new(_("Name: "));
128         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
129         gtk_table_attach(owner_table, label, 0, 1, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
130         label = gtk_label_new(subject_commonname);
131         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
132         gtk_table_attach(owner_table, label, 1, 2, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
133         
134         label = gtk_label_new(_("Organization: "));
135         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
136         gtk_table_attach(owner_table, label, 0, 1, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
137         label = gtk_label_new(subject_organization);
138         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
139         gtk_table_attach(owner_table, label, 1, 2, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
140         
141         label = gtk_label_new(_("Location: "));
142         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
143         gtk_table_attach(owner_table, label, 0, 1, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
144         label = gtk_label_new(subject_location);
145         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
146         gtk_table_attach(owner_table, label, 1, 2, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
147
148         label = gtk_label_new(_("Name: "));
149         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
150         gtk_table_attach(signer_table, label, 0, 1, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
151         label = gtk_label_new(issuer_commonname);
152         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
153         gtk_table_attach(signer_table, label, 1, 2, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
154         
155         label = gtk_label_new(_("Organization: "));
156         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
157         gtk_table_attach(signer_table, label, 0, 1, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
158         label = gtk_label_new(issuer_organization);
159         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
160         gtk_table_attach(signer_table, label, 1, 2, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
161         
162         label = gtk_label_new(_("Location: "));
163         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
164         gtk_table_attach(signer_table, label, 0, 1, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
165         label = gtk_label_new(issuer_location);
166         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
167         gtk_table_attach(signer_table, label, 1, 2, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
168
169         label = gtk_label_new(_("Fingerprint: "));
170         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
171         gtk_table_attach(status_table, label, 0, 1, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
172         label = gtk_label_new(fingerprint);
173         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
174         gtk_table_attach(status_table, label, 1, 2, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
175         label = gtk_label_new(_("Signature status: "));
176         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
177         gtk_table_attach(status_table, label, 0, 1, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
178         label = gtk_label_new(sig_status);
179         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
180         gtk_table_attach(status_table, label, 1, 2, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
181         
182         gtk_container_add(GTK_CONTAINER(frame_owner), GTK_WIDGET(owner_table));
183         gtk_container_add(GTK_CONTAINER(frame_signer), GTK_WIDGET(signer_table));
184         gtk_container_add(GTK_CONTAINER(frame_status), GTK_WIDGET(status_table));
185         
186         gtk_box_pack_end(GTK_BOX(hbox), frame_signer, TRUE, TRUE, 0);
187         gtk_box_pack_end(GTK_BOX(hbox), frame_owner, TRUE, TRUE, 0);
188         gtk_box_pack_end(GTK_BOX(vbox), frame_status, TRUE, TRUE, 0);
189         gtk_box_pack_end(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
190         
191         gtk_widget_show_all(vbox);
192         
193         g_free(issuer_commonname);
194         g_free(issuer_location);
195         g_free(issuer_organization);
196         g_free(subject_commonname);
197         g_free(subject_location);
198         g_free(subject_organization);
199         g_free(fingerprint);
200         g_free(sig_status);
201         
202         return vbox;
203 }
204
205 static gboolean sslcert_ask_hook(gpointer source, gpointer data)
206 {
207         SSLCertHookData *hookdata = (SSLCertHookData *)source;
208         if (hookdata == NULL) {
209                 return FALSE;
210         }
211         if (hookdata->old_cert == NULL)
212                 hookdata->accept = sslcertwindow_ask_new_cert(hookdata->cert);
213         else
214                 hookdata->accept = sslcertwindow_ask_changed_cert(hookdata->old_cert, hookdata->cert);
215
216         return TRUE;
217 }
218
219 void sslcertwindow_register_hook(void)
220 {
221         hooks_register_hook(SSLCERT_ASK_HOOKLIST, sslcert_ask_hook, NULL);
222 }
223
224 void sslcertwindow_show_cert(SSLCertificate *cert)
225 {
226         GtkWidget *cert_widget = cert_presenter(cert);
227         gchar *buf;
228         
229         buf = g_strdup_printf(_("SSL certificate for %s"), cert->host);
230         alertpanel_full(buf, NULL, GTK_STOCK_CLOSE, NULL, NULL,
231                         FALSE, cert_widget, ALERT_NOTICE, G_ALERTDEFAULT);
232         g_free(buf);
233 }
234
235 gboolean sslcertwindow_ask_new_cert(SSLCertificate *cert)
236 {
237         gchar *buf, *sig_status;
238         AlertValue val;
239         GtkWidget *vbox;
240         GtkWidget *label;
241         GtkWidget *button;
242         GtkWidget *cert_widget;
243         
244         vbox = gtk_vbox_new(FALSE, 5);
245         buf = g_strdup_printf(_("Certificate for %s is unknown.\nDo you want to accept it?"), cert->host);
246         label = gtk_label_new(buf);
247         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
248         gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
249         g_free(buf);
250         
251         sig_status = ssl_certificate_check_signer(cert->x509_cert);
252
253         if (sig_status==NULL)
254                 sig_status = g_strdup(_("correct"));
255
256         buf = g_strdup_printf(_("Signature status: %s"), sig_status);
257         label = gtk_label_new(buf);
258         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
259         gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
260         g_free(buf);
261         g_free(sig_status);
262         
263         button = gtk_expander_new_with_mnemonic(_("_View certificate"));
264         gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
265         cert_widget = cert_presenter(cert);
266         gtk_container_add(GTK_CONTAINER(button), cert_widget);
267
268         val = alertpanel_full(_("Unknown SSL Certificate"), NULL,
269                               _("_Accept and save"), _("_Cancel connection"), NULL,
270                               FALSE, vbox, ALERT_QUESTION, G_ALERTDEFAULT);
271         
272         return (val == G_ALERTDEFAULT);
273 }
274
275 gboolean sslcertwindow_ask_changed_cert(SSLCertificate *old_cert, SSLCertificate *new_cert)
276 {
277         GtkWidget *old_cert_widget = cert_presenter(old_cert);
278         GtkWidget *new_cert_widget = cert_presenter(new_cert);
279         GtkWidget *vbox;
280         gchar *buf, *sig_status;
281         GtkWidget *vbox2;
282         GtkWidget *label;
283         GtkWidget *button;
284         AlertValue val;
285         
286         vbox = gtk_vbox_new(FALSE, 5);
287         label = gtk_label_new(_("New certificate:"));
288         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
289         gtk_box_pack_end(GTK_BOX(vbox), new_cert_widget, TRUE, TRUE, 0);
290         gtk_box_pack_end(GTK_BOX(vbox), label, TRUE, TRUE, 0);
291         gtk_box_pack_end(GTK_BOX(vbox), gtk_hseparator_new(), TRUE, TRUE, 0);
292         label = gtk_label_new(_("Known certificate:"));
293         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
294         gtk_box_pack_end(GTK_BOX(vbox), old_cert_widget, TRUE, TRUE, 0);
295         gtk_box_pack_end(GTK_BOX(vbox), label, TRUE, TRUE, 0);
296         gtk_widget_show_all(vbox);
297         
298         vbox2 = gtk_vbox_new(FALSE, 5);
299         buf = g_strdup_printf(_("Certificate for %s has changed. Do you want to accept it?"), new_cert->host);
300         label = gtk_label_new(buf);
301         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
302         gtk_box_pack_start(GTK_BOX(vbox2), label, TRUE, TRUE, 0);
303         g_free(buf);
304         
305         sig_status = ssl_certificate_check_signer(new_cert->x509_cert);
306
307         if (sig_status==NULL)
308                 sig_status = g_strdup(_("correct"));
309
310         buf = g_strdup_printf(_("Signature status: %s"), sig_status);
311         label = gtk_label_new(buf);
312         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
313         gtk_box_pack_start(GTK_BOX(vbox2), label, TRUE, TRUE, 0);
314         g_free(buf);
315         g_free(sig_status);
316         
317         button = gtk_expander_new_with_mnemonic(_("_View certificates"));
318         gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0);
319         gtk_container_add(GTK_CONTAINER(button), vbox);
320
321         val = alertpanel_full(_("Changed SSL Certificate"), NULL,
322                               _("_Accept and save"), _("_Cancel connection"), NULL,
323                               FALSE, vbox2, ALERT_WARNING, G_ALERTDEFAULT);
324         
325         return (val == G_ALERTDEFAULT);
326 }
327 #endif