2008-10-10 [colin] 3.6.1cvs1
[claws.git] / src / gtk / sslcertwindow.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2007 Colin Leroy <colin@colino.net> 
4  * and the Claws Mail team
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 3 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, see <http://www.gnu.org/licenses/>.
18  * 
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #endif
24
25 #if (defined(USE_OPENSSL) || defined (USE_GNUTLS))
26
27 #if USE_OPENSSL
28 #include <openssl/ssl.h>
29 #else
30 #include <gnutls/gnutls.h>
31 #include <gnutls/x509.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <string.h>
37 #endif
38 #include <glib.h>
39 #include <glib/gi18n.h>
40 #include <gtk/gtk.h>
41
42 #include "prefs_common.h"
43 #include "defs.h"
44 #include "ssl_certificate.h"
45 #include "utils.h"
46 #include "alertpanel.h"
47 #include "hooks.h"
48
49 static gboolean sslcertwindow_ask_new_cert(SSLCertificate *cert);
50 static gboolean sslcertwindow_ask_expired_cert(SSLCertificate *cert);
51 static gboolean sslcertwindow_ask_changed_cert(SSLCertificate *old_cert, SSLCertificate *new_cert);
52
53 static GtkWidget *cert_presenter(SSLCertificate *cert)
54 {
55         GtkWidget *vbox = NULL;
56         GtkWidget *hbox = NULL;
57         GtkWidget *frame_owner = NULL;
58         GtkWidget *frame_signer = NULL;
59         GtkWidget *frame_status = NULL;
60         GtkTable *owner_table = NULL;
61         GtkTable *signer_table = NULL;
62         GtkTable *status_table = NULL;
63         GtkWidget *label = NULL;
64         
65         char *issuer_commonname, *issuer_location, *issuer_organization;
66         char *subject_commonname, *subject_location, *subject_organization;
67         char *sig_status, *exp_date;
68         char *md5_fingerprint, *sha1_fingerprint, *fingerprint;
69 #if USE_OPENSSL
70         unsigned int n;
71 #else
72         size_t n;
73 #endif
74         char buf[100];
75         unsigned char md[128];  
76 #if USE_OPENSSL
77         ASN1_TIME *validity;
78 #else
79         char *tmp;
80 #endif
81         time_t exp_time_t;
82         struct tm lt;
83
84         /* issuer */    
85 #if USE_OPENSSL
86         if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), 
87                                        NID_commonName, buf, 100) >= 0)
88                 issuer_commonname = g_strdup(buf);
89         else
90                 issuer_commonname = g_strdup(_("<not in certificate>"));
91         if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), 
92                                        NID_localityName, buf, 100) >= 0) {
93                 issuer_location = g_strdup(buf);
94                 if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), 
95                                        NID_countryName, buf, 100) >= 0)
96                         issuer_location = g_strconcat(issuer_location,", ",buf, NULL);
97         } else if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), 
98                                        NID_countryName, buf, 100) >= 0)
99                 issuer_location = g_strdup(buf);
100         else
101                 issuer_location = g_strdup(_("<not in certificate>"));
102
103         if (X509_NAME_get_text_by_NID(X509_get_issuer_name(cert->x509_cert), 
104                                        NID_organizationName, buf, 100) >= 0)
105                 issuer_organization = g_strdup(buf);
106         else 
107                 issuer_organization = g_strdup(_("<not in certificate>"));
108          
109         /* subject */   
110         if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), 
111                                        NID_commonName, buf, 100) >= 0)
112                 subject_commonname = g_strdup(buf);
113         else
114                 subject_commonname = g_strdup(_("<not in certificate>"));
115         if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), 
116                                        NID_localityName, buf, 100) >= 0) {
117                 subject_location = g_strdup(buf);
118                 if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), 
119                                        NID_countryName, buf, 100) >= 0)
120                         subject_location = g_strconcat(subject_location,", ",buf, NULL);
121         } else if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), 
122                                        NID_countryName, buf, 100) >= 0)
123                 subject_location = g_strdup(buf);
124         else
125                 subject_location = g_strdup(_("<not in certificate>"));
126
127         if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert->x509_cert), 
128                                        NID_organizationName, buf, 100) >= 0)
129                 subject_organization = g_strdup(buf);
130         else 
131                 subject_organization = g_strdup(_("<not in certificate>"));
132          
133         if ((validity = X509_get_notAfter(cert->x509_cert)) != NULL) {
134                 exp_time_t = asn1toTime(validity);
135         } else {
136                 exp_time_t = (time_t)0;
137         }
138 #else
139         issuer_commonname = g_malloc(BUFFSIZE);
140         issuer_location = g_malloc(BUFFSIZE);
141         issuer_organization = g_malloc(BUFFSIZE);
142         subject_commonname = g_malloc(BUFFSIZE);
143         subject_location = g_malloc(BUFFSIZE);
144         subject_organization = g_malloc(BUFFSIZE);
145
146         n = BUFFSIZE;
147         if (gnutls_x509_crt_get_issuer_dn_by_oid(cert->x509_cert, 
148                 GNUTLS_OID_X520_COMMON_NAME, 0, 0, issuer_commonname, &n))
149                 strncpy(issuer_commonname, _("<not in certificate>"), BUFFSIZE);
150         n = BUFFSIZE;
151
152         if (gnutls_x509_crt_get_issuer_dn_by_oid(cert->x509_cert, 
153                 GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, issuer_location, &n)) {
154                 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert->x509_cert, 
155                         GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, issuer_location, &n)) {
156                         strncpy(issuer_location, _("<not in certificate>"), BUFFSIZE);
157                 }
158         } else {
159                 tmp = g_malloc(BUFFSIZE);
160                 if (gnutls_x509_crt_get_issuer_dn_by_oid(cert->x509_cert, 
161                         GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, tmp, &n) == 0) {
162                         strncat(issuer_location, ", ", BUFFSIZE-strlen(issuer_location));
163                         strncat(issuer_location, tmp, BUFFSIZE-strlen(issuer_location));
164                 }
165                 g_free(tmp);
166         }
167
168         n = BUFFSIZE;
169         if (gnutls_x509_crt_get_issuer_dn_by_oid(cert->x509_cert, 
170                 GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, issuer_organization, &n))
171                 strncpy(issuer_organization, _("<not in certificate>"), BUFFSIZE);
172
173         n = BUFFSIZE;
174         if (gnutls_x509_crt_get_dn_by_oid(cert->x509_cert, 
175                 GNUTLS_OID_X520_COMMON_NAME, 0, 0, subject_commonname, &n))
176                 strncpy(subject_commonname, _("<not in certificate>"), BUFFSIZE);
177         n = BUFFSIZE;
178
179         if (gnutls_x509_crt_get_dn_by_oid(cert->x509_cert, 
180                 GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, subject_location, &n)) {
181                 if (gnutls_x509_crt_get_dn_by_oid(cert->x509_cert, 
182                         GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, subject_location, &n)) {
183                         strncpy(subject_location, _("<not in certificate>"), BUFFSIZE);
184                 }
185         } else {
186                 tmp = g_malloc(BUFFSIZE);
187                 if (gnutls_x509_crt_get_dn_by_oid(cert->x509_cert, 
188                         GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, tmp, &n) == 0) {
189                         strncat(subject_location, ", ", BUFFSIZE-strlen(subject_location));
190                         strncat(subject_location, tmp, BUFFSIZE-strlen(subject_location));
191                 }
192                 g_free(tmp);
193         }
194
195         n = BUFFSIZE;
196         if (gnutls_x509_crt_get_dn_by_oid(cert->x509_cert, 
197                 GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, subject_organization, &n))
198                 strncpy(subject_organization, _("<not in certificate>"), BUFFSIZE);
199                 
200         exp_time_t = gnutls_x509_crt_get_expiration_time(cert->x509_cert);
201 #endif  
202
203         memset(buf, 0, sizeof(buf));
204         if (exp_time_t > 0) {
205                 strftime(buf, sizeof(buf)-1, prefs_common.date_format, localtime_r(&exp_time_t, &lt));
206                 exp_date = (*buf) ? g_strdup(buf):g_strdup("?");
207         } else
208                 exp_date = g_strdup("");
209
210         /* fingerprint */
211 #if USE_OPENSSL
212         X509_digest(cert->x509_cert, EVP_md5(), md, &n);
213         md5_fingerprint = readable_fingerprint(md, (int)n);
214         X509_digest(cert->x509_cert, EVP_sha1(), md, &n);
215         sha1_fingerprint = readable_fingerprint(md, (int)n);
216
217         /* signature */
218         sig_status = ssl_certificate_check_signer(cert->x509_cert);
219 #else
220         n = 128;
221         gnutls_x509_crt_get_fingerprint(cert->x509_cert, GNUTLS_DIG_MD5, md, &n);
222         md5_fingerprint = readable_fingerprint(md, (int)n);
223         n = 128;
224         gnutls_x509_crt_get_fingerprint(cert->x509_cert, GNUTLS_DIG_SHA1, md, &n);
225         sha1_fingerprint = readable_fingerprint(md, (int)n);
226
227         /* signature */
228         sig_status = ssl_certificate_check_signer(cert->x509_cert, cert->status);
229 #endif
230
231         if (sig_status==NULL)
232                 sig_status = g_strdup(_("correct"));
233
234         vbox = gtk_vbox_new(FALSE, 5);
235         hbox = gtk_hbox_new(FALSE, 5);
236         
237         frame_owner  = gtk_frame_new(_("Owner"));
238         frame_signer = gtk_frame_new(_("Signer"));
239         frame_status = gtk_frame_new(_("Status"));
240         
241         owner_table = GTK_TABLE(gtk_table_new(3, 2, FALSE));
242         signer_table = GTK_TABLE(gtk_table_new(3, 2, FALSE));
243         status_table = GTK_TABLE(gtk_table_new(3, 2, FALSE));
244         
245         label = gtk_label_new(_("Name: "));
246         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
247         gtk_table_attach(owner_table, label, 0, 1, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
248         label = gtk_label_new(subject_commonname);
249         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
250         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
251         gtk_table_attach(owner_table, label, 1, 2, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
252         
253         label = gtk_label_new(_("Organization: "));
254         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
255         gtk_table_attach(owner_table, label, 0, 1, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
256         label = gtk_label_new(subject_organization);
257         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
258         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
259         gtk_table_attach(owner_table, label, 1, 2, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
260         
261         label = gtk_label_new(_("Location: "));
262         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
263         gtk_table_attach(owner_table, label, 0, 1, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
264         label = gtk_label_new(subject_location);
265         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
266         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
267         gtk_table_attach(owner_table, label, 1, 2, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
268
269         label = gtk_label_new(_("Name: "));
270         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
271         gtk_table_attach(signer_table, label, 0, 1, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
272         label = gtk_label_new(issuer_commonname);
273         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
274         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
275         gtk_table_attach(signer_table, label, 1, 2, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
276         
277         label = gtk_label_new(_("Organization: "));
278         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
279         gtk_table_attach(signer_table, label, 0, 1, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
280         label = gtk_label_new(issuer_organization);
281         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
282         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
283         gtk_table_attach(signer_table, label, 1, 2, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
284         
285         label = gtk_label_new(_("Location: "));
286         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
287         gtk_table_attach(signer_table, label, 0, 1, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
288         label = gtk_label_new(issuer_location);
289         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
290         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
291         gtk_table_attach(signer_table, label, 1, 2, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
292
293         label = gtk_label_new(_("Fingerprint: \n"));
294         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
295         gtk_table_attach(status_table, label, 0, 1, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
296         fingerprint = g_strdup_printf("MD5: %s\nSHA1: %s", 
297                         md5_fingerprint, sha1_fingerprint);
298         label = gtk_label_new(fingerprint);
299         g_free(fingerprint);
300         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
301         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
302         gtk_table_attach(status_table, label, 1, 2, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
303         label = gtk_label_new(_("Signature status: "));
304         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
305         gtk_table_attach(status_table, label, 0, 1, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
306         label = gtk_label_new(sig_status);
307         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
308         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
309         gtk_table_attach(status_table, label, 1, 2, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
310         label = gtk_label_new(_("Expires on: "));
311         gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
312         gtk_table_attach(status_table, label, 0, 1, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
313         label = gtk_label_new(exp_date);
314         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
315         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
316         gtk_table_attach(status_table, label, 1, 2, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
317         
318         gtk_container_add(GTK_CONTAINER(frame_owner), GTK_WIDGET(owner_table));
319         gtk_container_add(GTK_CONTAINER(frame_signer), GTK_WIDGET(signer_table));
320         gtk_container_add(GTK_CONTAINER(frame_status), GTK_WIDGET(status_table));
321         
322         gtk_box_pack_end(GTK_BOX(hbox), frame_signer, TRUE, TRUE, 0);
323         gtk_box_pack_end(GTK_BOX(hbox), frame_owner, TRUE, TRUE, 0);
324         gtk_box_pack_end(GTK_BOX(vbox), frame_status, TRUE, TRUE, 0);
325         gtk_box_pack_end(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
326         
327         gtk_widget_show_all(vbox);
328         
329         g_free(issuer_commonname);
330         g_free(issuer_location);
331         g_free(issuer_organization);
332         g_free(subject_commonname);
333         g_free(subject_location);
334         g_free(subject_organization);
335         g_free(md5_fingerprint);
336         g_free(sha1_fingerprint);
337         g_free(sig_status);
338         g_free(exp_date);
339         return vbox;
340 }
341
342 static gboolean sslcert_ask_hook(gpointer source, gpointer data)
343 {
344         SSLCertHookData *hookdata = (SSLCertHookData *)source;
345
346         if (prefs_common.skip_ssl_cert_check)
347                 return TRUE;
348
349         if (hookdata == NULL) {
350                 return FALSE;
351         }
352         if (hookdata->old_cert == NULL) {
353                 if (hookdata->expired)
354                         hookdata->accept = sslcertwindow_ask_expired_cert(hookdata->cert);
355                 else
356                         hookdata->accept = sslcertwindow_ask_new_cert(hookdata->cert);
357         } else {
358                 hookdata->accept = sslcertwindow_ask_changed_cert(hookdata->old_cert, hookdata->cert);
359         }
360         return TRUE;
361 }
362
363 void sslcertwindow_register_hook(void)
364 {
365         hooks_register_hook(SSLCERT_ASK_HOOKLIST, sslcert_ask_hook, NULL);
366 }
367
368 void sslcertwindow_show_cert(SSLCertificate *cert)
369 {
370         GtkWidget *cert_widget = cert_presenter(cert);
371         gchar *buf;
372         
373         buf = g_strdup_printf(_("SSL certificate for %s"), cert->host);
374         alertpanel_full(buf, NULL, GTK_STOCK_CLOSE, NULL, NULL,
375                         FALSE, cert_widget, ALERT_NOTICE, G_ALERTDEFAULT);
376         g_free(buf);
377 }
378
379 static gboolean sslcertwindow_ask_new_cert(SSLCertificate *cert)
380 {
381         gchar *buf, *sig_status;
382         AlertValue val;
383         GtkWidget *vbox;
384         GtkWidget *label;
385         GtkWidget *button;
386         GtkWidget *cert_widget;
387         
388         vbox = gtk_vbox_new(FALSE, 5);
389         buf = g_strdup_printf(_("Certificate for %s is unknown.\nDo you want to accept it?"), cert->host);
390         label = gtk_label_new(buf);
391         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
392         gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
393         g_free(buf);
394         
395 #if USE_OPENSSL
396         sig_status = ssl_certificate_check_signer(cert->x509_cert);
397 #else
398         sig_status = ssl_certificate_check_signer(cert->x509_cert, cert->status);
399 #endif
400         if (sig_status==NULL)
401                 sig_status = g_strdup(_("correct"));
402
403         buf = g_strdup_printf(_("Signature status: %s"), sig_status);
404         label = gtk_label_new(buf);
405         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
406         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
407         gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
408         g_free(buf);
409         g_free(sig_status);
410         
411         button = gtk_expander_new_with_mnemonic(_("_View certificate"));
412         gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
413         cert_widget = cert_presenter(cert);
414         gtk_container_add(GTK_CONTAINER(button), cert_widget);
415
416         val = alertpanel_full(_("Unknown SSL Certificate"), NULL,
417                               _("_Cancel connection"), _("_Accept and save"), NULL,
418                               FALSE, vbox, ALERT_QUESTION, G_ALERTDEFAULT);
419         
420         return (val == G_ALERTALTERNATE);
421 }
422
423 static gboolean sslcertwindow_ask_expired_cert(SSLCertificate *cert)
424 {
425         gchar *buf, *sig_status;
426         AlertValue val;
427         GtkWidget *vbox;
428         GtkWidget *label;
429         GtkWidget *button;
430         GtkWidget *cert_widget;
431         
432         vbox = gtk_vbox_new(FALSE, 5);
433         buf = g_strdup_printf(_("Certificate for %s is expired.\nDo you want to continue?"), cert->host);
434         label = gtk_label_new(buf);
435         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
436         gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
437         g_free(buf);
438         
439 #if USE_OPENSSL
440         sig_status = ssl_certificate_check_signer(cert->x509_cert);
441 #else
442         sig_status = ssl_certificate_check_signer(cert->x509_cert, cert->status);
443 #endif
444
445         if (sig_status==NULL)
446                 sig_status = g_strdup(_("correct"));
447
448         buf = g_strdup_printf(_("Signature status: %s"), sig_status);
449         label = gtk_label_new(buf);
450         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
451         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
452         gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
453         g_free(buf);
454         g_free(sig_status);
455         
456         button = gtk_expander_new_with_mnemonic(_("_View certificate"));
457         gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
458         cert_widget = cert_presenter(cert);
459         gtk_container_add(GTK_CONTAINER(button), cert_widget);
460
461         val = alertpanel_full(_("Expired SSL Certificate"), NULL,
462                               _("_Cancel connection"), _("_Accept"), NULL,
463                               FALSE, vbox, ALERT_QUESTION, G_ALERTDEFAULT);
464         
465         return (val == G_ALERTALTERNATE);
466 }
467
468 static gboolean sslcertwindow_ask_changed_cert(SSLCertificate *old_cert, SSLCertificate *new_cert)
469 {
470         GtkWidget *old_cert_widget = cert_presenter(old_cert);
471         GtkWidget *new_cert_widget = cert_presenter(new_cert);
472         GtkWidget *vbox;
473         gchar *buf, *sig_status;
474         GtkWidget *vbox2;
475         GtkWidget *label;
476         GtkWidget *button;
477         AlertValue val;
478         
479         vbox = gtk_vbox_new(FALSE, 5);
480         label = gtk_label_new(_("New certificate:"));
481         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
482         gtk_box_pack_end(GTK_BOX(vbox), new_cert_widget, TRUE, TRUE, 0);
483         gtk_box_pack_end(GTK_BOX(vbox), label, TRUE, TRUE, 0);
484         gtk_box_pack_end(GTK_BOX(vbox), gtk_hseparator_new(), TRUE, TRUE, 0);
485         label = gtk_label_new(_("Known certificate:"));
486         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
487         gtk_box_pack_end(GTK_BOX(vbox), old_cert_widget, TRUE, TRUE, 0);
488         gtk_box_pack_end(GTK_BOX(vbox), label, TRUE, TRUE, 0);
489         gtk_widget_show_all(vbox);
490         
491         vbox2 = gtk_vbox_new(FALSE, 5);
492         buf = g_strdup_printf(_("Certificate for %s has changed. Do you want to accept it?"), new_cert->host);
493         label = gtk_label_new(buf);
494         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
495         gtk_box_pack_start(GTK_BOX(vbox2), label, TRUE, TRUE, 0);
496         g_free(buf);
497         
498 #if USE_OPENSSL
499         sig_status = ssl_certificate_check_signer(new_cert->x509_cert);
500 #else
501         sig_status = ssl_certificate_check_signer(new_cert->x509_cert, new_cert->status);
502 #endif
503
504         if (sig_status==NULL)
505                 sig_status = g_strdup(_("correct"));
506
507         buf = g_strdup_printf(_("Signature status: %s"), sig_status);
508         label = gtk_label_new(buf);
509         gtk_label_set_selectable(GTK_LABEL(label), TRUE);
510         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
511         gtk_box_pack_start(GTK_BOX(vbox2), label, TRUE, TRUE, 0);
512         g_free(buf);
513         g_free(sig_status);
514         
515         button = gtk_expander_new_with_mnemonic(_("_View certificates"));
516         gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0);
517         gtk_container_add(GTK_CONTAINER(button), vbox);
518
519         val = alertpanel_full(_("Changed SSL Certificate"), NULL,
520                               _("_Cancel connection"), _("_Accept and save"), NULL,
521                               FALSE, vbox2, ALERT_WARNING, G_ALERTDEFAULT);
522         
523         return (val == G_ALERTALTERNATE);
524 }
525 #endif