/* * GtkNSSDialogs.cpp * * Copyright (C) 2003 Crispin Flowerday * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id$ */ /* * This file provides Gtk implementations of the mozilla Certificate dialogs * such as the ones displayed when connecting to a site with a self-signed * or expired certificate. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_MOZILLA_PSM #include "MozillaPrivate.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ALLOW_PRIVATE_STRINGS #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "GtkNSSDialogs.h" #include "ephy-file-helpers.h" #include "ephy-glade.h" #include "ephy-gui.h" NS_DEFINE_CID (kX509CertCID, NS_IX509CERT_IID); NS_DEFINE_CID (kASN1ObjectCID, NS_IASN1OBJECT_IID); enum { NSSDIALOG_RESPONSE_VIEW_CERT = 10 }; GtkNSSDialogs::GtkNSSDialogs () { } GtkNSSDialogs::~GtkNSSDialogs () { } NS_IMPL_ISUPPORTS2 (GtkNSSDialogs, nsICertificateDialogs, nsIBadCertListener) /** * Call the mozilla service to display a certificate */ static void view_certificate (nsIInterfaceRequestor *ctx, nsIX509Cert *cert) { nsresult rv; nsCOMPtr certDialogs = do_GetService (NS_CERTIFICATEDIALOGS_CONTRACTID, &rv); g_return_if_fail (NS_SUCCEEDED (rv)); certDialogs->ViewCert (ctx, cert); } /** * Indent a widget according the HIG * * @returns: The new indented widget */ static GtkWidget* higgy_indent_widget (GtkWidget *widget) { GtkWidget *hbox; GtkWidget *label; hbox = gtk_hbox_new (FALSE, 6); label = gtk_label_new (""); gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, TRUE, 6); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX(hbox), widget, TRUE, TRUE, 0); return hbox; } /** * Setup up a dialog with the correct HIG'gy spacings, adding the content_widget */ static void higgy_setup_dialog (GtkDialog *dialog, const gchar *stock_icon, GtkWidget **content_label, GtkWidget **content_vbox) { GtkWidget *hbox, *label, *image, *vbox; g_return_if_fail (GTK_IS_DIALOG (dialog)); g_return_if_fail (content_label); gtk_dialog_set_has_separator (dialog, FALSE); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); hbox = gtk_hbox_new (FALSE, 12); gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); image = gtk_image_new_from_stock (stock_icon, GTK_ICON_SIZE_DIALOG); gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); vbox = gtk_vbox_new (FALSE, 12); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); label = gtk_label_new (NULL); gtk_label_set_use_markup (GTK_LABEL (label), TRUE); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_selectable (GTK_LABEL (label), TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_widget_show (image); gtk_widget_show (vbox); gtk_widget_show (hbox); gtk_widget_show (label); /* Set up the spacing for the dialog internal widgets */ gtk_box_set_spacing (GTK_BOX(dialog->action_area), 6); gtk_box_set_spacing (GTK_BOX(dialog->vbox), 12); *content_label = label; if (content_vbox) { *content_vbox = vbox; } } /** * Display a dialog box, showing 'View Certificate', 'Cancel', * and 'Accept' buttons. Optionally a checkbox can be shown, * or the text can be NULL to avoid it being displayed * * @returns: GTK_RESPONSE_ACCEPT if the user clicked Accept */ static gint display_cert_warning_box (nsIInterfaceRequestor *ctx, nsIX509Cert *cert, const char *markup_text, const char *checkbox_text, gboolean *checkbox_value, const char *affirmative_text) { GtkWidget *dialog, *label, *checkbox, *vbox; int res; nsCOMPtr parent = do_GetInterface (ctx); GtkWidget *gparent = MozillaFindGtkParent (parent); g_return_val_if_fail (markup_text, GTK_RESPONSE_CANCEL); g_return_val_if_fail (!checkbox_text || checkbox_value, GTK_RESPONSE_CANCEL); dialog = gtk_dialog_new_with_buttons ("", gparent ? GTK_WINDOW (gparent) : NULL, GTK_DIALOG_DESTROY_WITH_PARENT, NULL); higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_WARNING, &label, &vbox); /* Add the buttons */ gtk_dialog_add_button (GTK_DIALOG (dialog), _("_View Certificate"), NSSDIALOG_RESPONSE_VIEW_CERT); gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); if (affirmative_text == NULL) { affirmative_text = _("_Accept"); } gtk_dialog_add_button (GTK_DIALOG (dialog), affirmative_text, GTK_RESPONSE_ACCEPT); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); if (checkbox_text) { checkbox = gtk_check_button_new_with_mnemonic (checkbox_text); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), *checkbox_value); gtk_box_pack_start (GTK_BOX (vbox), checkbox, TRUE, TRUE, 0); } else { checkbox = 0; } gtk_label_set_markup (GTK_LABEL (label), markup_text); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); gtk_widget_show_all (dialog); while (1) { res = gtk_dialog_run (GTK_DIALOG (dialog)); if (res == NSSDIALOG_RESPONSE_VIEW_CERT) { view_certificate (ctx, cert); continue; } break; } if (res == GTK_RESPONSE_ACCEPT && checkbox) { *checkbox_value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox)); } gtk_widget_destroy (dialog); return res; } NS_IMETHODIMP GtkNSSDialogs::ConfirmMismatchDomain (nsIInterfaceRequestor *ctx, const nsACString &targetURL, nsIX509Cert *cert, PRBool *_retval) { nsAutoString commonName; char *ttTargetUrl, *ttCommonName, *first, *second, *msg; int res; cert->GetCommonName (commonName); ttTargetUrl = g_strdup_printf ("\"%s\"", PromiseFlatCString(targetURL).get()); ttCommonName = g_strdup_printf ("\"%s\"", NS_ConvertUTF16toUTF8(commonName).get()); first = g_strdup_printf (_("The site %s returned security information for " "%s. It is possible that someone is intercepting " "your communication to obtain your confidential " "information."), ttTargetUrl, ttCommonName); second = g_strdup_printf (_("You should only accept the security information if you " "trust %s and %s."), ttTargetUrl, ttCommonName); msg = g_strdup_printf ("%s\n\n%s\n\n%s", _("Accept incorrect security information?"), first, second); res = display_cert_warning_box (ctx, cert, msg, NULL, NULL, NULL); g_free (ttTargetUrl); g_free (ttCommonName); g_free (second); g_free (first); g_free (msg); *_retval = (res == GTK_RESPONSE_ACCEPT); return NS_OK; } NS_IMETHODIMP GtkNSSDialogs::ConfirmUnknownIssuer (nsIInterfaceRequestor *ctx, nsIX509Cert *cert, PRInt16 *outAddType, PRBool *_retval) { gboolean accept_perm = FALSE; nsAutoString commonName; char *ttCommonName, *secondary, *tertiary, *msg; int res; cert->GetCommonName (commonName); ttCommonName = g_strdup_printf ("\"%s\"", NS_ConvertUTF16toUTF8(commonName).get()); secondary = g_strdup_printf (_("Your browser was unable to trust %s. " "It is possible that someone is intercepting your " "communication to obtain your confidential information."), ttCommonName); tertiary = g_strdup_printf (_("You should only connect to the site if you are certain " "you are connected to %s."), ttCommonName); msg = g_strdup_printf ("%s\n\n%s\n\n%s", _("Connect to untrusted site?"), secondary, tertiary); res = display_cert_warning_box (ctx, cert, msg, _("_Don't show this message again for this site"), &accept_perm, _("Co_nnect")); g_free (ttCommonName); g_free (tertiary); g_free (secondary); g_free (msg); if (res != GTK_RESPONSE_ACCEPT) { *_retval = PR_FALSE; *outAddType = UNINIT_ADD_FLAG; } else { if (accept_perm) { *_retval = PR_TRUE; *outAddType = ADD_TRUSTED_PERMANENTLY; } else { *_retval = PR_TRUE; *outAddType = ADD_TRUSTED_FOR_SESSION; } } return NS_OK; } /* boolean confirmCertExpired (in nsIInterfaceRequestor socketInfo, in nsIX509Cert cert); */ NS_IMETHODIMP GtkNSSDialogs::ConfirmCertExpired (nsIInterfaceRequestor *ctx, nsIX509Cert *cert, PRBool *_retval) { nsresult rv; PRTime now = PR_Now(); PRTime notAfter, notBefore, timeToUse; PRInt64 normalizedTime; nsAutoString commonName; time_t t; struct tm tm; char formattedDate[128]; char *fdate; const char *primary, *text; char *ttCommonName, *secondary, *msg; *_retval = PR_FALSE; nsCOMPtr validity; rv = cert->GetValidity (getter_AddRefs(validity)); if (NS_FAILED(rv)) return rv; rv = validity->GetNotAfter (¬After); if (NS_FAILED(rv)) return rv; rv = validity->GetNotBefore (¬Before); if (NS_FAILED(rv)) return rv; if (LL_CMP(now, >, notAfter)) { primary = _("Accept expired security information?"); text = _("The security information for %s " "expired on %s."); timeToUse = notAfter; } else { primary = _("Accept not yet valid security information?"); text = _("The security information for %s isn't valid until %s."); timeToUse = notBefore; } cert->GetCommonName (commonName); LL_DIV (normalizedTime, timeToUse, PR_USEC_PER_SEC); LL_L2UI (t, normalizedTime); /* To translators: this a time format that is used while displaying the * expiry or start date of an SSL certificate, for the format see * strftime(3) */ strftime (formattedDate, sizeof(formattedDate), _("%a %d %b %Y"), localtime_r (&t, &tm)); fdate = g_locale_to_utf8 (formattedDate, -1, NULL, NULL, NULL); ttCommonName = g_strdup_printf ("\"%s\"", NS_ConvertUTF16toUTF8(commonName).get()); secondary = g_strdup_printf (text, ttCommonName, fdate); msg = g_strdup_printf ("%s\n\n%s\n\n%s", primary, secondary, _("You should ensure that your computer's time is correct.")); int res = display_cert_warning_box (ctx, cert, msg, NULL, NULL, NULL); g_free (fdate); g_free (msg); g_free (secondary); g_free (ttCommonName); *_retval = (res == GTK_RESPONSE_ACCEPT); return NS_OK; } /* void notifyCrlNextupdate (in nsIInterfaceRequestor socketInfo, in AUTF8String targetURL, in nsIX509Cert cert); */ NS_IMETHODIMP GtkNSSDialogs::NotifyCrlNextupdate (nsIInterfaceRequestor *ctx, const nsACString & targetURL, nsIX509Cert *cert) { GtkWidget *dialog, *label; char *ttCommonName, *ttTargetUrl, *msg, *primary, *secondary; nsAutoString commonName; nsCOMPtr parent = do_GetInterface (ctx); GtkWidget *gparent = MozillaFindGtkParent (parent); dialog = gtk_dialog_new_with_buttons ("", GTK_WINDOW (gparent), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_ERROR, &label, NULL); cert->GetCommonName (commonName); ttCommonName = g_strdup_printf ("\"%s\"", NS_ConvertUTF16toUTF8(commonName).get()); ttTargetUrl = g_strdup_printf ("\"%s\"", PromiseFlatCString(targetURL).get()); primary = g_strdup_printf (_("Cannot establish connection to %s."), ttTargetUrl); secondary = g_strdup_printf (_("The certificate revocation list (CRL) from %s " "needs to be updated."), ttCommonName); msg = g_strdup_printf ("%s\n\n%s\n\n%s", primary, secondary, _("Please ask your system administrator for assistance.")); gtk_label_set_markup (GTK_LABEL (label), msg); g_free (primary); g_free (secondary); g_free (msg); g_free (ttCommonName); g_free (ttTargetUrl); gtk_widget_show_all (dialog); g_signal_connect (G_OBJECT (dialog), "response", (GCallback)gtk_widget_destroy, NULL); gtk_widget_show_all (dialog); return NS_OK; } NS_IMETHODIMP GtkNSSDialogs::ConfirmDownloadCACert(nsIInterfaceRequestor *ctx, nsIX509Cert *cert, PRUint32 *_trust, PRBool *_retval) { GtkWidget *dialog, *label, *content_vbox, *vbox; GtkWidget *check_ssl, *check_software; char *ttCommonName, *msg, *tertiary; nsCOMPtr parent = do_GetInterface (ctx); GtkWidget *gparent = MozillaFindGtkParent (parent); dialog = gtk_dialog_new_with_buttons ("", GTK_WINDOW (gparent), GTK_DIALOG_DESTROY_WITH_PARENT, _("_View Certificate"), NSSDIALOG_RESPONSE_VIEW_CERT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, _("_Trust CA"), GTK_RESPONSE_ACCEPT, NULL); higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_WARNING, &label, &content_vbox); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); nsAutoString commonName; cert->GetCommonName (commonName); ttCommonName = g_strdup_printf ("\"%s\"", NS_ConvertUTF16toUTF8(commonName).get()); tertiary = g_strdup_printf (_("Trust %s to identify:"), ttCommonName ); g_free (ttCommonName); msg = g_strdup_printf ("%s\n\n%s\n\n%s", _("Trust new Certificate Authority?"), _("Before trusting a Certificate Authority (CA) you should " "verify the certificate is authentic."), tertiary); gtk_label_set_markup (GTK_LABEL (label), msg); g_free (tertiary); g_free (msg); vbox = gtk_vbox_new (FALSE, 6); check_ssl = gtk_check_button_new_with_mnemonic (_("_Web sites")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_ssl), TRUE); gtk_box_pack_start (GTK_BOX(vbox), check_ssl, TRUE, TRUE, 0); check_software = gtk_check_button_new_with_mnemonic (_("_Software developers")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_software), FALSE); gtk_box_pack_start (GTK_BOX(vbox), check_software, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (content_vbox), higgy_indent_widget (vbox), FALSE, FALSE, 0); gtk_widget_show_all (dialog); int ret; while (1) { ret = gtk_dialog_run (GTK_DIALOG (dialog)); if (ret == NSSDIALOG_RESPONSE_VIEW_CERT) { view_certificate (ctx, cert); continue; } break; } if (ret != GTK_RESPONSE_ACCEPT) { *_retval = PR_FALSE; } else { *_trust = nsIX509CertDB::UNTRUSTED; if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_ssl))) { *_trust |= nsIX509CertDB::TRUSTED_SSL; } if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_software))) { *_trust |= nsIX509CertDB::TRUSTED_SSL; } *_retval = PR_TRUE; } gtk_widget_destroy (dialog); return NS_OK; } NS_IMETHODIMP GtkNSSDialogs::NotifyCACertExists (nsIInterfaceRequestor *ctx) { GtkWidget *dialog, *label; char * msg; nsCOMPtr parent = do_GetInterface (ctx); GtkWidget *gparent = MozillaFindGtkParent (parent); dialog = gtk_dialog_new_with_buttons ("", GTK_WINDOW (gparent), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_ERROR, &label, NULL); msg = g_strdup_printf ("%s\n\n%s", _("Certificate already exists."), _("The certificate has already been imported.")); gtk_label_set_markup (GTK_LABEL (label), msg); g_free (msg); g_signal_connect (G_OBJECT (dialog), "response", (GCallback)gtk_widget_destroy, NULL); gtk_widget_show_all (dialog); return NS_OK; } struct SetPasswordCallback { GtkWidget *entry1; GtkWidget *entry2; GtkWidget *widget; }; static void set_password_entry_changed_cb (GtkEditable *editable, void * _data) { SetPasswordCallback * data = (SetPasswordCallback*)_data; gchar * text1 = gtk_editable_get_chars (GTK_EDITABLE(data->entry1), 0, -1); gchar * text2 = gtk_editable_get_chars (GTK_EDITABLE(data->entry2), 0, -1); if (strcmp (text1, text2) == 0) { gtk_widget_set_sensitive (data->widget, TRUE); } else { gtk_widget_set_sensitive (data->widget, FALSE); } g_free (text1); g_free (text2); } /** * Calculate the quality of a password. The algorithm used is taken * directly from mozilla in: * $MOZSRC/security/manager/pki/resources/content/password.js */ static void password_quality_meter_cb (GtkEditable *editable, GtkWidget *progress) { gchar * text = gtk_editable_get_chars (editable, 0, -1); /* Get the length */ glong length = g_utf8_strlen (text, -1); /* Count the number of number, symbols and uppercase chars */ gint uppercase = 0; gint symbols = 0; gint numbers = 0; for( const gchar * p = text; *p; p = g_utf8_find_next_char (p, NULL) ) { gunichar uc = g_utf8_get_char(p); if (g_unichar_isdigit (uc)) { numbers++; } else if (g_unichar_isupper (uc)) { uppercase++; } else if (g_unichar_islower (uc)) { /* Not counted */ } else if (g_unichar_isgraph (uc)) { symbols++; } } if (length > 5) length = 5; if (numbers > 3) numbers = 3; if (symbols > 3) symbols = 3; if (uppercase > 3) uppercase = 3; gint strength = ((length*10)-20) + (numbers*10) + (symbols*15) + (uppercase*10); if (strength < 0) strength = 0; if (strength > 100) strength = 100; gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress), (strength/100.0)); g_free (text); } NS_IMETHODIMP GtkNSSDialogs::SetPKCS12FilePassword(nsIInterfaceRequestor *ctx, nsAString &_password, PRBool *_retval) { GtkWidget *dialog, *table, *entry1, *entry2, *button, *label, *vbox; GtkWidget *progress; char *msg; nsCOMPtr parent = do_GetInterface (ctx); GtkWidget *gparent = MozillaFindGtkParent (parent); dialog = gtk_dialog_new_with_buttons ("", GTK_WINDOW (gparent), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_QUESTION, &label, &vbox); button = gtk_button_new_with_mnemonic (_("_Backup Certificate")); gtk_widget_show (button); gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); msg = g_strdup_printf ("%s\n\n%s", _("Select password."), _("Select a password to protect this certificate.")); gtk_label_set_markup (GTK_LABEL (label), msg); g_free (msg); table = gtk_table_new (3, 3, FALSE); gtk_table_set_row_spacings (GTK_TABLE (table), 6); gtk_table_set_col_spacings (GTK_TABLE (table), 6); gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); label = gtk_label_new (NULL); entry1 = gtk_entry_new (); entry2 = gtk_entry_new (); gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("_Password:")); gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry1); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_entry_set_visibility (GTK_ENTRY (entry1), FALSE); g_signal_connect_swapped (entry1, "activate", (GCallback)gtk_widget_grab_focus, entry2); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0 ); gtk_table_attach (GTK_TABLE (table), entry1, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0 ); label = gtk_label_new (NULL); gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("Con_firm password:")); gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry2); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_entry_set_visibility (GTK_ENTRY (entry2), FALSE); gtk_entry_set_activates_default (GTK_ENTRY (entry2), TRUE); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0 ); gtk_table_attach (GTK_TABLE (table), entry2, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0 ); /* TODO: We need a better password quality meter */ label = gtk_label_new (_("Password quality:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); progress = gtk_progress_bar_new (); gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress), 0.0); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0 ); gtk_table_attach (GTK_TABLE (table), progress, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0 ); SetPasswordCallback callback_data = { entry1, entry2, button }; g_signal_connect (entry1, "changed", (GCallback)set_password_entry_changed_cb, &callback_data); g_signal_connect (entry1, "changed", (GCallback)password_quality_meter_cb, progress); g_signal_connect (entry2, "changed", (GCallback)set_password_entry_changed_cb, &callback_data); gtk_widget_show_all (dialog); int ret = gtk_dialog_run (GTK_DIALOG (dialog)); if (ret != GTK_RESPONSE_OK) { *_retval = PR_FALSE; } else { gchar * text = gtk_editable_get_chars (GTK_EDITABLE (entry1), 0, -1); CopyUTF8toUTF16 (text, _password); g_free (text); *_retval = PR_TRUE; } gtk_widget_destroy (dialog); return NS_OK; } NS_IMETHODIMP GtkNSSDialogs::GetPKCS12FilePassword(nsIInterfaceRequestor *ctx, nsAString &_password, PRBool *_retval) { GtkWidget *dialog, *hbox, *label, *entry, *vbox; char *msg; nsCOMPtr parent = do_GetInterface (ctx); GtkWidget *gparent = MozillaFindGtkParent (parent); dialog = gtk_dialog_new_with_buttons ("", GTK_WINDOW (gparent), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, _("I_mport Certificate"), GTK_RESPONSE_OK, NULL); higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_QUESTION, &label, &vbox); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); msg = g_strdup_printf ("%s\n\n%s", _("Password required."), _("Enter the password for this certificate.")); gtk_label_set_markup (GTK_LABEL (label), msg); g_free (msg); hbox = gtk_hbox_new (FALSE, 6); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new (NULL); entry = gtk_entry_new (); gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("_Password:")); gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry); gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE); gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); gtk_widget_show_all (dialog); int ret = gtk_dialog_run (GTK_DIALOG (dialog)); if (ret != GTK_RESPONSE_OK) { *_retval = PR_FALSE; } else { gchar * text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); CopyUTF8toUTF16 (text, _password); g_free (text); *_retval = PR_TRUE; } gtk_widget_destroy (dialog); return NS_OK; } static void set_table_row (GtkWidget *table, int row, const char *title, GtkWidget *label) { GtkWidget *header; char buf[64]; g_snprintf (buf, sizeof(buf), "%s", title); header = gtk_label_new (buf); gtk_label_set_use_markup (GTK_LABEL(header), TRUE); gtk_misc_set_alignment (GTK_MISC(header), 0, 0); gtk_widget_show (header); gtk_table_attach (GTK_TABLE (table), header, 0, 1, row, row+1, GTK_FILL, GTK_FILL, 0, 0); gtk_misc_set_alignment (GTK_MISC(label), 0, 0); gtk_widget_show (label); gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, row, row+1); } NS_IMETHODIMP GtkNSSDialogs::CrlImportStatusDialog(nsIInterfaceRequestor *ctx, nsICRLInfo *crl) { GtkWidget *dialog, *label, *table, *vbox; nsresult rv; char *msg; nsCOMPtr parent = do_GetInterface (ctx); GtkWidget *gparent = MozillaFindGtkParent (parent); dialog = gtk_dialog_new_with_buttons ("", GTK_WINDOW (gparent), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_INFO, &label, &vbox); msg = g_strdup_printf ("%s\n\n%s", _("Certificate Revocation list successfully imported."), _("Certificate Revocation list (CRL) imported:")); gtk_label_set_markup (GTK_LABEL (label), msg); g_free (msg); table = gtk_table_new (2, 3, FALSE); gtk_table_set_row_spacings (GTK_TABLE (table), 6); gtk_table_set_col_spacings (GTK_TABLE (table), 6); nsAutoString org, orgUnit, nextUpdate; rv = crl->GetOrganization (org); if (NS_FAILED(rv)) return rv; rv = crl->GetOrganizationalUnit (orgUnit); if (NS_FAILED(rv)) return rv; rv = crl->GetNextUpdateLocale (nextUpdate); if (NS_FAILED(rv)) return rv; label = gtk_label_new (NS_ConvertUTF16toUTF8(org).get()); set_table_row (table, 0, _("Organization:"), label); label = gtk_label_new (NS_ConvertUTF16toUTF8(orgUnit).get()); set_table_row (table, 1, _("Unit:"), label); label = gtk_label_new (NS_ConvertUTF16toUTF8(nextUpdate).get()); set_table_row (table, 2, _("Next Update:"), label); gtk_box_pack_start (GTK_BOX (vbox), higgy_indent_widget (table), FALSE, FALSE, 0); gtk_widget_show_all (dialog); g_signal_connect (G_OBJECT (dialog), "response", (GCallback)gtk_widget_destroy, NULL); gtk_widget_show_all (dialog); return NS_OK; } /** * Help function to fill in the labels on the General tab */ static void set_label_cert_attribute (GladeXML* gxml, const char* label_id, nsAutoString &value) { GtkWidget *label; label = glade_xml_get_widget (gxml, label_id); g_return_if_fail (GTK_IS_LABEL (label)); if (value.IsEmpty()) { gtk_label_set_use_markup (GTK_LABEL (label), TRUE); char *msg = g_strdup_printf ("<%s>", _("Not part of certificate")); gtk_label_set_markup (GTK_LABEL (label), msg); g_free (msg); } else { gtk_label_set_use_markup (GTK_LABEL (label), FALSE); gtk_label_set_text (GTK_LABEL (label), NS_ConvertUTF16toUTF8(value).get()); } } /** * Do that actual filling in of the certificate tree */ static gboolean fill_cert_chain_tree (GtkTreeView *treeview, nsIArray *certChain) { nsresult rv; GtkTreeModel * model = gtk_tree_view_get_model (treeview); GtkTreeIter parent; PRUint32 numCerts; rv = certChain->GetLength (&numCerts); if (NS_FAILED(rv) || numCerts < 1) return FALSE; for (int i = (int)numCerts-1 ; i >= 0; i--) { nsCOMPtr nsCert; rv = certChain->QueryElementAt (i, kX509CertCID, getter_AddRefs(nsCert)); if (NS_FAILED(rv)) return FALSE; GtkTreeIter iter; gtk_tree_store_append (GTK_TREE_STORE (model), &iter, (i == (int)numCerts-1) ? NULL : &parent); nsAutoString value; rv = nsCert->GetCommonName (value); if (NS_FAILED(rv)) return FALSE; nsIX509Cert *nsCertP = nsCert; if (!value.IsEmpty()) { gtk_tree_store_set (GTK_TREE_STORE(model), &iter, 0, NS_ConvertUTF16toUTF8(value).get(), 1, nsCertP, -1); } else { char * title; rv = nsCert->GetWindowTitle (&title); if (NS_FAILED(rv)) return FALSE; gtk_tree_store_set (GTK_TREE_STORE(model), &iter, 0, title, 1, nsCertP, -1); nsMemory::Free (title); } parent = iter; } gtk_tree_view_expand_all (GTK_TREE_VIEW (treeview)); /* And select the last entry */ GtkTreeSelection *select = gtk_tree_view_get_selection (treeview); GtkTreePath *path = gtk_tree_model_get_path (model, &parent); gtk_tree_selection_select_path (select, path); gtk_tree_path_free (path); return TRUE; } /** * Add an ASN object to the treeview, recursing if the object was a * sequence */ static void add_asn1_object_to_tree(GtkTreeModel *model, nsIASN1Object *object, GtkTreeIter *parent) { nsAutoString dispNameU; object->GetDisplayName(dispNameU); GtkTreeIter iter; gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent); gtk_tree_store_set (GTK_TREE_STORE(model), &iter, 0, NS_ConvertUTF16toUTF8(dispNameU).get(), 1, object, -1); nsCOMPtr sequence(do_QueryInterface(object)); if (!sequence) return; nsCOMPtr asn1Objects; sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); PRUint32 numObjects; asn1Objects->GetLength(&numObjects); if (!asn1Objects) return; for (PRUint32 i = 0; i < numObjects ; i++) { nsCOMPtr currObject; asn1Objects->QueryElementAt (i, kASN1ObjectCID, getter_AddRefs (currObject)); add_asn1_object_to_tree (model, currObject, &iter); } } /** * Update the "Certificate Fields" treeview when a different cert * is selected in the hierarchy text view */ static void cert_chain_tree_view_selection_changed_cb (GtkTreeSelection *selection, GtkWidget* tree_view) { GtkTreeIter iter; nsIX509Cert *nsCert; nsresult rv; GtkTreeModel * model; if (gtk_tree_selection_get_selected (selection, &model, &iter)) { gtk_tree_model_get (model, &iter, 1, &nsCert, -1); nsCOMPtr object; rv = nsCert->GetASN1Structure (getter_AddRefs(object)); if (NS_FAILED(rv)) return; model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); gtk_tree_store_clear (GTK_TREE_STORE (model)); add_asn1_object_to_tree (model, object, NULL); gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view)); } } /** * When the "Certificate Field" treeview is changed, update the * text_view to display the value of the currently selected field */ static void field_tree_view_selection_changed_cb (GtkTreeSelection *selection, GtkWidget* text_view) { GtkTreeIter iter; GtkTreeModel *model; GtkTextBuffer * text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)); if (gtk_tree_selection_get_selected (selection, &model, &iter)) { nsIASN1Object *object; nsAutoString dispValU; gtk_tree_model_get (model, &iter, 1, &object, -1); object->GetDisplayValue(dispValU); gtk_text_buffer_set_text (text_buffer, NS_ConvertUTF16toUTF8(dispValU).get(), -1); } else { gtk_text_buffer_set_text (text_buffer, "", 0); } } /** * Setup the various treeviews, the textview, and fill the treeviews */ static gboolean setup_view_cert_tree (GtkWidget *dialog, GladeXML*gxml, nsIArray *certChain) { GtkCellRenderer *renderer; GtkWidget *chain_tree_view, *field_tree_view, *text_view; PangoFontDescription *monospace_font_desc; GConfClient *conf_client; char *monospace_font; chain_tree_view = glade_xml_get_widget (gxml, "treeview_cert_chain"); field_tree_view = glade_xml_get_widget (gxml, "treeview_cert_info"); text_view = glade_xml_get_widget (gxml, "textview_field_value"); /* Setup the certificate chain view */ GtkTreeStore *store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); gtk_tree_view_set_model (GTK_TREE_VIEW (chain_tree_view), GTK_TREE_MODEL (store)); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (chain_tree_view), 0, "Certificate", renderer, "text", 0, NULL); GtkTreeSelection *select = gtk_tree_view_get_selection (GTK_TREE_VIEW (chain_tree_view)); gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); g_signal_connect (G_OBJECT (select), "changed", G_CALLBACK (cert_chain_tree_view_selection_changed_cb), field_tree_view); /* Setup the certificate field view */ store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); gtk_tree_view_set_model (GTK_TREE_VIEW (field_tree_view), GTK_TREE_MODEL (store)); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (field_tree_view), 0, "Certificate Field", renderer, "text", 0, NULL); select = gtk_tree_view_get_selection (GTK_TREE_VIEW (field_tree_view)); gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); g_signal_connect (G_OBJECT (select), "changed", G_CALLBACK (field_tree_view_selection_changed_cb), text_view); /* Get the text_view displaying a propertional font * * Pick up the monospace font from desktop preferences */ conf_client = gconf_client_get_default (); monospace_font = gconf_client_get_string (conf_client, "/desktop/gnome/interface/monospace_font_name", NULL); if (monospace_font) { monospace_font_desc = pango_font_description_from_string (monospace_font); gtk_widget_modify_font (text_view, monospace_font_desc); pango_font_description_free (monospace_font_desc); } g_object_unref (conf_client); /* And fill the certificate chain tree */ return fill_cert_chain_tree (GTK_TREE_VIEW (chain_tree_view), certChain); } /* void viewCert (in nsIX509Cert cert); */ NS_IMETHODIMP GtkNSSDialogs::ViewCert(nsIInterfaceRequestor *ctx, nsIX509Cert *cert) { GtkWidget *dialog, *widget; GladeXML *gxml; nsAutoString value; nsresult rv; PRUint32 verifystate, count; PRUnichar ** usage; GtkSizeGroup * sizegroup; gxml = ephy_glade_widget_new (ephy_file ("certificate-dialogs.glade"), "viewcert_dialog", &dialog, NULL, NULL); nsCOMPtr parent = do_GetInterface (ctx); GtkWidget *gparent = MozillaFindGtkParent (parent); gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(gparent)); gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); gtk_window_set_title (GTK_WINDOW (dialog), _("Certificate Properties")); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); /* Set up the GtkSizeGroup so that the columns line up */ sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); widget = glade_xml_get_widget (gxml, "label_size1"); gtk_size_group_add_widget (sizegroup, widget); widget = glade_xml_get_widget (gxml, "label_size2"); gtk_size_group_add_widget (sizegroup, widget); widget = glade_xml_get_widget (gxml, "label_size3"); gtk_size_group_add_widget (sizegroup, widget); widget = glade_xml_get_widget (gxml, "label_size4"); gtk_size_group_add_widget (sizegroup, widget); g_object_unref (sizegroup); rv = cert->GetUsagesArray (FALSE, &verifystate, &count, &usage); if (NS_FAILED(rv)) return rv; const char * text; switch (verifystate) { case nsIX509Cert::VERIFIED_OK: text = _("This certificate has been verified for the following uses:"); break; case nsIX509Cert::CERT_REVOKED: text = _("Could not verify this certificate because it has been revoked."); break; case nsIX509Cert::CERT_EXPIRED: text = _("Could not verify this certificate because it has expired."); break; case nsIX509Cert::CERT_NOT_TRUSTED: text = _("Could not verify this certificate because it is not trusted."); break; case nsIX509Cert::ISSUER_NOT_TRUSTED: text = _("Could not verify this certificate because the issuer is not trusted."); break; case nsIX509Cert::ISSUER_UNKNOWN: text = _("Could not verify this certificate because the issuer is unknown."); break; case nsIX509Cert::INVALID_CA: text = _("Could not verify this certificate because the CA certificate is invalid."); break; case nsIX509Cert::NOT_VERIFIED_UNKNOWN: case nsIX509Cert::USAGE_NOT_ALLOWED: default: text = _("Could not verify this certificate for unknown reasons."); } char *msg = g_strdup_printf ("%s", text); widget = glade_xml_get_widget (gxml, "label_verify_text"); g_return_val_if_fail (GTK_IS_LABEL (widget), NS_ERROR_FAILURE); gtk_label_set_markup (GTK_LABEL (widget), msg); g_free (msg); if (count > 0) { GtkWidget *vbox = gtk_vbox_new (FALSE, 3); GtkWidget *indent; for (PRUint32 i = 0 ; i < count ; i++) { const nsACString &msg = NS_ConvertUTF16toUTF8 (usage[i]); GtkWidget *label = gtk_label_new(PromiseFlatCString(msg).get()); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); nsMemory::Free (usage[i]); } nsMemory::Free (usage); indent = higgy_indent_widget (vbox); widget = glade_xml_get_widget (gxml, "vbox_validity"); g_return_val_if_fail (GTK_IS_BOX (widget), NS_ERROR_FAILURE); gtk_box_pack_start (GTK_BOX (widget), indent, FALSE, FALSE, 0); } cert->GetCommonName (value); set_label_cert_attribute (gxml, "label_cn", value); cert->GetOrganization (value); set_label_cert_attribute (gxml, "label_o", value); cert->GetOrganizationalUnit (value); set_label_cert_attribute (gxml, "label_ou", value); cert->GetSerialNumber (value); set_label_cert_attribute (gxml, "label_serial", value); rv = cert->GetIssuerCommonName (value); if (NS_FAILED(rv)) return rv; set_label_cert_attribute (gxml, "label_issuer_cn", value); cert->GetIssuerOrganization (value); set_label_cert_attribute (gxml, "label_issuer_o", value); cert->GetIssuerOrganizationUnit (value); set_label_cert_attribute (gxml, "label_issuer_ou", value); nsCOMPtr validity; rv = cert->GetValidity (getter_AddRefs(validity)); if (NS_FAILED(rv)) return rv; rv = validity->GetNotAfterLocalDay (value); if (NS_FAILED(rv)) return rv; set_label_cert_attribute (gxml, "label_notafter", value); rv = validity->GetNotBeforeLocalDay (value); if (NS_FAILED(rv)) return rv; set_label_cert_attribute (gxml, "label_notbefore", value); cert->GetSha1Fingerprint (value); set_label_cert_attribute (gxml, "label_sha_print", value); cert->GetMd5Fingerprint (value); set_label_cert_attribute (gxml, "label_md5_print", value); /* Hold a reference to each certificate in the chain while the * dialog is displayed, this holds the reference for the ASN * objects as well */ nsCOMPtr certChain; rv = cert->GetChain (getter_AddRefs(certChain)); if (NS_FAILED(rv)) return rv; gboolean ret = setup_view_cert_tree (dialog, gxml, certChain); if (ret == FALSE) return NS_ERROR_FAILURE; g_object_unref (gxml); gtk_widget_show_all (dialog); int res; while (1) { res = gtk_dialog_run (GTK_DIALOG (dialog)); if (res == GTK_RESPONSE_HELP) { ephy_gui_help (GTK_WINDOW (dialog), "epiphany", "using-certificate-viewer"); continue; } break; } gtk_widget_destroy (dialog); return NS_OK; } #endif