mostly implement a viewer for certificates.
2003-11-26 Chris Toshok <toshok@ximian.com> * gui/certificate-viewer.[ch]: mostly implement a viewer for certificates. * gui/smime-ui.glade: fingerprints-sh1 -> fingerprints-sha1. * gui/certificate-manager.c (import_your): new function, use e-pkcs12 to implement it. (initialize_yourcerts_ui): hook up the import button. (view_contact): new function, bring up the certificate viewer. (initialize_contactcerts_ui): hook up the view button. (view_ca): new function, bring up the certificate viewer. (initialize_authoritycerts_ui): hook up the view button. * gui/Makefile.am (libevolution_smime_la_SOURCES): add certificate-viewer.[ch] * lib/e-cert.c (e_cert_dispose): free all the new cached foo. (e_cert_populate): populate all the new cached foo. (e_cert_get_issuer_cn): new function. (e_cert_get_issuer_org): same. (e_cert_get_issuer_org_unit): same. (e_cert_get_issued_on_time): same. (e_cert_get_issued_on): same. (e_cert_get_expires_on_time): same. (e_cert_get_expires_on): same. (e_cert_get_serial_number): same. (e_cert_get_sha1_fingerprint): same. (e_cert_get_md5_fingerprint): same. * lib/e-cert.h: add prototypes for lots more accessors. * lib/e-cert-db.c (e_cert_db_find_cert_by_key): fix typo. (e_cert_db_find_cert_by_email_address): call CERT_DestroyCertificate to free the cert. (default_nickname): new function. (e_cert_db_import_user_cert): implement. (e_cert_db_import_server_cert): add blurb. * lib/e-pkcs12.[ch]: new files. * lib/Makefile.am (libessmime_la_SOURCES): add e-pkcs12.[ch] svn path=/trunk/; revision=23486
This commit is contained in:
parent
30ff908fcd
commit
4e4c16760a
@ -1,3 +1,47 @@
|
||||
2003-11-26 Chris Toshok <toshok@ximian.com>
|
||||
|
||||
* gui/certificate-viewer.[ch]: mostly implement a viewer for
|
||||
certificates.
|
||||
|
||||
* gui/smime-ui.glade: fingerprints-sh1 -> fingerprints-sha1.
|
||||
|
||||
* gui/certificate-manager.c (import_your): new function, use
|
||||
e-pkcs12 to implement it.
|
||||
(initialize_yourcerts_ui): hook up the import button.
|
||||
(view_contact): new function, bring up the certificate viewer.
|
||||
(initialize_contactcerts_ui): hook up the view button.
|
||||
(view_ca): new function, bring up the certificate viewer.
|
||||
(initialize_authoritycerts_ui): hook up the view button.
|
||||
|
||||
* gui/Makefile.am (libevolution_smime_la_SOURCES): add
|
||||
certificate-viewer.[ch]
|
||||
|
||||
* lib/e-cert.c (e_cert_dispose): free all the new cached foo.
|
||||
(e_cert_populate): populate all the new cached foo.
|
||||
(e_cert_get_issuer_cn): new function.
|
||||
(e_cert_get_issuer_org): same.
|
||||
(e_cert_get_issuer_org_unit): same.
|
||||
(e_cert_get_issued_on_time): same.
|
||||
(e_cert_get_issued_on): same.
|
||||
(e_cert_get_expires_on_time): same.
|
||||
(e_cert_get_expires_on): same.
|
||||
(e_cert_get_serial_number): same.
|
||||
(e_cert_get_sha1_fingerprint): same.
|
||||
(e_cert_get_md5_fingerprint): same.
|
||||
|
||||
* lib/e-cert.h: add prototypes for lots more accessors.
|
||||
|
||||
* lib/e-cert-db.c (e_cert_db_find_cert_by_key): fix typo.
|
||||
(e_cert_db_find_cert_by_email_address): call
|
||||
CERT_DestroyCertificate to free the cert.
|
||||
(default_nickname): new function.
|
||||
(e_cert_db_import_user_cert): implement.
|
||||
(e_cert_db_import_server_cert): add blurb.
|
||||
|
||||
* lib/e-pkcs12.[ch]: new files.
|
||||
|
||||
* lib/Makefile.am (libessmime_la_SOURCES): add e-pkcs12.[ch]
|
||||
|
||||
2003-11-12 Not Zed <NotZed@Ximian.com>
|
||||
|
||||
* gui/smime-ui.glade: added cert_selector widget to be placed
|
||||
|
@ -23,6 +23,8 @@ noinst_LTLIBRARIES = libevolution-smime.la
|
||||
libevolution_smime_la_SOURCES = \
|
||||
certificate-manager.c \
|
||||
certificate-manager.h \
|
||||
certificate-viewer.c \
|
||||
certificate-viewer.h \
|
||||
e-cert-selector.c \
|
||||
e-cert-selector.h
|
||||
|
||||
|
@ -29,9 +29,11 @@
|
||||
#include <glade/glade.h>
|
||||
#include "evolution-config-control.h"
|
||||
#include "certificate-manager.h"
|
||||
#include "certificate-viewer.h"
|
||||
|
||||
#include "e-cert.h"
|
||||
#include "e-cert-db.h"
|
||||
#include "e-pkcs12.h"
|
||||
|
||||
#include "nss.h"
|
||||
#include <cms.h>
|
||||
@ -114,6 +116,26 @@ handle_selection_changed (GtkTreeSelection *selection,
|
||||
gtk_widget_set_sensitive (view_button, cert_selected);
|
||||
}
|
||||
|
||||
static void
|
||||
import_your (GtkWidget *widget, CertificateManagerData *cfm)
|
||||
{
|
||||
GtkWidget *filesel = gtk_file_selection_new (_("Select a cert to import..."));
|
||||
|
||||
if (GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (filesel))) {
|
||||
const char *filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel));
|
||||
EPKCS12 *pkcs12 = e_pkcs12_new ();
|
||||
|
||||
if (e_pkcs12_import_from_file (pkcs12, filename, NULL /* XXX */)) {
|
||||
/* there's no telling how many certificates were added during the import,
|
||||
so we blow away the contact cert display and regenerate it. */
|
||||
unload_certs (cfm, E_CERT_USER);
|
||||
load_certs (cfm, E_CERT_USER, add_user_cert);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_destroy (filesel);
|
||||
}
|
||||
|
||||
static void
|
||||
yourcerts_selection_changed (GtkTreeSelection *selection, CertificateManagerData *cfm)
|
||||
{
|
||||
@ -170,7 +192,7 @@ initialize_yourcerts_ui (CertificateManagerData *cfm)
|
||||
g_signal_connect (selection, "changed", G_CALLBACK (yourcerts_selection_changed), cfm);
|
||||
|
||||
if (cfm->import_your_button) {
|
||||
/* g_signal_connect */
|
||||
g_signal_connect (cfm->import_your_button, "clicked", G_CALLBACK (import_your), cfm);
|
||||
}
|
||||
|
||||
if (cfm->delete_your_button) {
|
||||
@ -190,6 +212,26 @@ initialize_yourcerts_ui (CertificateManagerData *cfm)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
view_contact (GtkWidget *widget, CertificateManagerData *cfm)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW(cfm->contactcerts_treeview)),
|
||||
NULL,
|
||||
&iter)) {
|
||||
ECert *cert;
|
||||
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (cfm->contactcerts_treemodel),
|
||||
&iter,
|
||||
3, &cert,
|
||||
-1);
|
||||
|
||||
if (cert)
|
||||
certificate_viewer_show (cert);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
import_contact (GtkWidget *widget, CertificateManagerData *cfm)
|
||||
{
|
||||
@ -297,6 +339,9 @@ initialize_contactcerts_ui (CertificateManagerData *cfm)
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->contactcerts_treeview));
|
||||
g_signal_connect (selection, "changed", G_CALLBACK (contactcerts_selection_changed), cfm);
|
||||
|
||||
if (cfm->view_contact_button)
|
||||
g_signal_connect (cfm->view_contact_button, "clicked", G_CALLBACK (view_contact), cfm);
|
||||
|
||||
if (cfm->import_contact_button)
|
||||
g_signal_connect (cfm->import_contact_button, "clicked", G_CALLBACK (import_contact), cfm);
|
||||
|
||||
@ -324,6 +369,26 @@ iter_string_compare (GtkTreeModel *model,
|
||||
return g_utf8_collate (string1, string2);
|
||||
}
|
||||
|
||||
static void
|
||||
view_ca (GtkWidget *widget, CertificateManagerData *cfm)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW(cfm->authoritycerts_treeview)),
|
||||
NULL,
|
||||
&iter)) {
|
||||
ECert *cert;
|
||||
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (cfm->authoritycerts_treemodel),
|
||||
&iter,
|
||||
1, &cert,
|
||||
-1);
|
||||
|
||||
if (cert)
|
||||
certificate_viewer_show (cert);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
import_ca (GtkWidget *widget, CertificateManagerData *cfm)
|
||||
{
|
||||
@ -421,6 +486,9 @@ initialize_authoritycerts_ui (CertificateManagerData *cfm)
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->authoritycerts_treeview));
|
||||
g_signal_connect (selection, "changed", G_CALLBACK (authoritycerts_selection_changed), cfm);
|
||||
|
||||
if (cfm->view_ca_button)
|
||||
g_signal_connect (cfm->view_ca_button, "clicked", G_CALLBACK (view_ca), cfm);
|
||||
|
||||
if (cfm->import_ca_button)
|
||||
g_signal_connect (cfm->import_ca_button, "clicked", G_CALLBACK (import_ca), cfm);
|
||||
|
||||
|
125
smime/gui/certificate-viewer.c
Normal file
125
smime/gui/certificate-viewer.c
Normal file
@ -0,0 +1,125 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* Authors: Chris Toshok <toshok@ximian.com>
|
||||
*
|
||||
* Copyright (C) 2003 Ximian, Inc. (www.ximian.com)
|
||||
*
|
||||
* 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 of the License, 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 Street #330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "certificate-viewer.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <libgnome/gnome-i18n.h>
|
||||
#include <glade/glade.h>
|
||||
|
||||
#define GLADE_FILE_NAME "smime-ui.glade"
|
||||
|
||||
typedef struct {
|
||||
GladeXML *gui;
|
||||
GtkWidget *dialog;
|
||||
} CertificateViewerData;
|
||||
|
||||
static void
|
||||
free_data (gpointer data, GObject *where_the_object_was)
|
||||
{
|
||||
CertificateViewerData *cvm = data;
|
||||
|
||||
g_object_unref (cvm->gui);
|
||||
g_free (cvm);
|
||||
}
|
||||
|
||||
|
||||
GtkWidget*
|
||||
certificate_viewer_show (ECert *cert)
|
||||
{
|
||||
CertificateViewerData *cvm_data;
|
||||
CERTCertificate *mcert;
|
||||
GtkWidget *label;
|
||||
const char *text;
|
||||
|
||||
mcert = e_cert_get_internal_cert (cert);
|
||||
|
||||
cvm_data = g_new0 (CertificateViewerData, 1);
|
||||
cvm_data->gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, NULL, NULL);
|
||||
|
||||
cvm_data->dialog = glade_xml_get_widget (cvm_data->gui, "certificate-viewer-dialog");
|
||||
|
||||
/* issued to */
|
||||
if (e_cert_get_cn (cert)) {
|
||||
label = glade_xml_get_widget (cvm_data->gui, "issued-to-cn");
|
||||
gtk_label_set_text (GTK_LABEL (label), e_cert_get_cn (cert));
|
||||
}
|
||||
|
||||
if (e_cert_get_org (cert)) {
|
||||
label = glade_xml_get_widget (cvm_data->gui, "issued-to-o");
|
||||
gtk_label_set_text (GTK_LABEL (label), e_cert_get_org (cert));
|
||||
}
|
||||
|
||||
if (e_cert_get_org_unit (cert)) {
|
||||
label = glade_xml_get_widget (cvm_data->gui, "issued-to-ou");
|
||||
gtk_label_set_text (GTK_LABEL (label), e_cert_get_org_unit (cert));
|
||||
}
|
||||
|
||||
text = e_cert_get_serial_number (cert);
|
||||
label = glade_xml_get_widget (cvm_data->gui, "issued-to-serial");
|
||||
gtk_label_set_text (GTK_LABEL (label), text);
|
||||
|
||||
/* issued by */
|
||||
if (e_cert_get_issuer_cn (cert)) {
|
||||
label = glade_xml_get_widget (cvm_data->gui, "issued-by-cn");
|
||||
gtk_label_set_text (GTK_LABEL (label), e_cert_get_issuer_cn (cert));
|
||||
}
|
||||
|
||||
if (e_cert_get_issuer_org (cert)) {
|
||||
label = glade_xml_get_widget (cvm_data->gui, "issued-by-o");
|
||||
gtk_label_set_text (GTK_LABEL (label), e_cert_get_issuer_org (cert));
|
||||
}
|
||||
|
||||
if (e_cert_get_issuer_org_unit (cert)) {
|
||||
label = glade_xml_get_widget (cvm_data->gui, "issued-by-ou");
|
||||
gtk_label_set_text (GTK_LABEL (label), e_cert_get_issuer_org_unit (cert));
|
||||
}
|
||||
|
||||
/* validity */
|
||||
if (e_cert_get_issued_on (cert)) {
|
||||
label = glade_xml_get_widget (cvm_data->gui, "validity-issued-on");
|
||||
gtk_label_set_text (GTK_LABEL (label), e_cert_get_issued_on (cert));
|
||||
}
|
||||
|
||||
if (e_cert_get_expires_on (cert)) {
|
||||
label = glade_xml_get_widget (cvm_data->gui, "validity-expires-on");
|
||||
gtk_label_set_text (GTK_LABEL (label), e_cert_get_expires_on (cert));
|
||||
}
|
||||
|
||||
/* fingerprints */
|
||||
text = e_cert_get_sha1_fingerprint (cert);
|
||||
label = glade_xml_get_widget (cvm_data->gui, "fingerprints-sha1");
|
||||
gtk_label_set_text (GTK_LABEL (label), text);
|
||||
|
||||
text = e_cert_get_md5_fingerprint (cert);
|
||||
label = glade_xml_get_widget (cvm_data->gui, "fingerprints-md5");
|
||||
gtk_label_set_text (GTK_LABEL (label), text);
|
||||
|
||||
g_object_weak_ref (G_OBJECT (cvm_data->dialog), free_data, cvm_data);
|
||||
|
||||
g_signal_connect (cvm_data->dialog, "response",
|
||||
G_CALLBACK (gtk_widget_destroy), NULL);
|
||||
|
||||
gtk_widget_show (cvm_data->dialog);
|
||||
return cvm_data->dialog;
|
||||
}
|
31
smime/gui/certificate-viewer.h
Normal file
31
smime/gui/certificate-viewer.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* Authors: Chris Toshok <toshok@ximian.com>
|
||||
*
|
||||
* Copyright (C) 2003 Ximian, Inc. (www.ximian.com)
|
||||
*
|
||||
* 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 of the License, 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 Street #330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CERTIFICATE_VIEWER_H_
|
||||
#define _CERTIFICATE_VIEWER_H
|
||||
|
||||
#include <gtk/gtkwidget.h>
|
||||
#include "e-cert.h"
|
||||
|
||||
GtkWidget* certificate_viewer_show (ECert *cert);
|
||||
|
||||
#endif /* _CERTIFICATE_VIEWER_H_ */
|
@ -745,7 +745,7 @@
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="fingerprints-sh1">
|
||||
<widget class="GtkLabel" id="fingerprints-sha1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes"><Not Part of Certificate></property>
|
||||
|
@ -25,4 +25,6 @@ libessmime_la_SOURCES = \
|
||||
e-cert-trust.c \
|
||||
e-cert-trust.h \
|
||||
e-cert-db.c \
|
||||
e-cert-db.h
|
||||
e-cert-db.h \
|
||||
e-pkcs12.c \
|
||||
e-pkcs12.h
|
||||
|
@ -68,7 +68,10 @@
|
||||
#include "nss.h"
|
||||
#include "pk11func.h"
|
||||
#include "certdb.h"
|
||||
#include <e-util/e-dialog-utils.h>
|
||||
#include "plstr.h"
|
||||
#include "prprf.h"
|
||||
#include "prmem.h"
|
||||
#include "e-util/e-dialog-utils.h"
|
||||
#include <gtk/gtkmessagedialog.h>
|
||||
#include <libgnome/gnome-i18n.h>
|
||||
#include <fcntl.h>
|
||||
@ -249,7 +252,7 @@ e_cert_db_find_cert_by_key (ECertDB *certdb,
|
||||
moduleID = NS_NSS_GET_LONG(keyItem.data);
|
||||
slotID = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG]);
|
||||
|
||||
/8 build the issuer/SN structure*/
|
||||
/* build the issuer/SN structure*/
|
||||
issuerSN.serialNumber.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*2]);
|
||||
issuerSN.derIssuer.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*3]);
|
||||
issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG*4];
|
||||
@ -312,21 +315,21 @@ e_cert_db_find_cert_by_email_address (ECertDB *certdb,
|
||||
PR_Now(), PR_TRUE);
|
||||
if (!certlist) {
|
||||
/* XXX gerror */
|
||||
/* XXX free any_cert */
|
||||
CERT_DestroyCertificate(any_cert);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SECSuccess != CERT_FilterCertListByUsage(certlist, certUsageEmailRecipient, PR_FALSE)) {
|
||||
/* XXX gerror */
|
||||
/* XXX free any_cert */
|
||||
/* XXX free certlist */
|
||||
CERT_DestroyCertificate(any_cert);
|
||||
/* XXX free certlist? */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist)) {
|
||||
/* XXX gerror */
|
||||
/* XXX free any_cert */
|
||||
/* XXX free certlist */
|
||||
CERT_DestroyCertificate(any_cert);
|
||||
/* XXX free certlist? */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -665,11 +668,208 @@ e_cert_db_import_email_cert (ECertDB *certdb,
|
||||
return rv;
|
||||
}
|
||||
|
||||
static char *
|
||||
default_nickname (CERTCertificate *cert)
|
||||
{
|
||||
/* nsNSSShutDownPreventionLock locker; */
|
||||
char *username = NULL;
|
||||
char *caname = NULL;
|
||||
char *nickname = NULL;
|
||||
char *tmp = NULL;
|
||||
int count;
|
||||
char *nickFmt=NULL, *nickFmtWithNum = NULL;
|
||||
CERTCertificate *dummycert;
|
||||
PK11SlotInfo *slot=NULL;
|
||||
CK_OBJECT_HANDLE keyHandle;
|
||||
|
||||
CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
|
||||
|
||||
username = CERT_GetCommonName(&cert->subject);
|
||||
if ( username == NULL )
|
||||
username = PL_strdup("");
|
||||
|
||||
if ( username == NULL )
|
||||
goto loser;
|
||||
|
||||
caname = CERT_GetOrgName(&cert->issuer);
|
||||
if ( caname == NULL )
|
||||
caname = PL_strdup("");
|
||||
|
||||
if ( caname == NULL )
|
||||
goto loser;
|
||||
|
||||
count = 1;
|
||||
|
||||
nickFmt = "%1$s's %2$s ID";
|
||||
nickFmtWithNum = "%1$s's %2$s ID #%3$d";
|
||||
|
||||
nickname = PR_smprintf(nickFmt, username, caname);
|
||||
/*
|
||||
* We need to see if the private key exists on a token, if it does
|
||||
* then we need to check for nicknames that already exist on the smart
|
||||
* card.
|
||||
*/
|
||||
slot = PK11_KeyForCertExists(cert, &keyHandle, NULL);
|
||||
if (slot == NULL) {
|
||||
goto loser;
|
||||
}
|
||||
if (!PK11_IsInternal(slot)) {
|
||||
tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), nickname);
|
||||
PR_Free(nickname);
|
||||
nickname = tmp;
|
||||
tmp = NULL;
|
||||
}
|
||||
tmp = nickname;
|
||||
while ( 1 ) {
|
||||
if ( count > 1 ) {
|
||||
nickname = PR_smprintf("%s #%d", tmp, count);
|
||||
}
|
||||
|
||||
if ( nickname == NULL )
|
||||
goto loser;
|
||||
|
||||
if (PK11_IsInternal(slot)) {
|
||||
/* look up the nickname to make sure it isn't in use already */
|
||||
dummycert = CERT_FindCertByNickname(defaultcertdb, nickname);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Check the cert against others that already live on the smart
|
||||
* card.
|
||||
*/
|
||||
dummycert = PK11_FindCertFromNickname(nickname, NULL);
|
||||
if (dummycert != NULL) {
|
||||
/*
|
||||
* Make sure the subject names are different.
|
||||
*/
|
||||
if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual) {
|
||||
/*
|
||||
* There is another certificate with the same nickname and
|
||||
* the same subject name on the smart card, so let's use this
|
||||
* nickname.
|
||||
*/
|
||||
CERT_DestroyCertificate(dummycert);
|
||||
dummycert = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( dummycert == NULL )
|
||||
goto done;
|
||||
|
||||
/* found a cert, destroy it and loop */
|
||||
CERT_DestroyCertificate(dummycert);
|
||||
if (tmp != nickname) PR_Free(nickname);
|
||||
count++;
|
||||
} /* end of while(1) */
|
||||
|
||||
loser:
|
||||
if ( nickname ) {
|
||||
PR_Free(nickname);
|
||||
}
|
||||
nickname = NULL;
|
||||
done:
|
||||
if ( caname ) {
|
||||
PR_Free(caname);
|
||||
}
|
||||
if ( username ) {
|
||||
PR_Free(username);
|
||||
}
|
||||
if (slot != NULL) {
|
||||
PK11_FreeSlot(slot);
|
||||
if (nickname != NULL) {
|
||||
tmp = nickname;
|
||||
nickname = strchr(tmp, ':');
|
||||
if (nickname != NULL) {
|
||||
nickname++;
|
||||
nickname = PL_strdup(nickname);
|
||||
PR_Free(tmp);
|
||||
tmp = NULL;
|
||||
} else {
|
||||
nickname = tmp;
|
||||
tmp = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
PR_FREEIF(tmp);
|
||||
return(nickname);
|
||||
}
|
||||
|
||||
gboolean
|
||||
e_cert_db_import_user_cert (ECertDB *certdb,
|
||||
char *data, guint32 length,
|
||||
GError **error)
|
||||
{
|
||||
/* nsNSSShutDownPreventionLock locker;*/
|
||||
PK11SlotInfo *slot;
|
||||
char * nickname = NULL;
|
||||
gboolean rv = FALSE;
|
||||
int numCACerts;
|
||||
SECItem *CACerts;
|
||||
CERTDERCerts * collectArgs;
|
||||
PRArenaPool *arena;
|
||||
CERTCertificate * cert=NULL;
|
||||
|
||||
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||||
if ( arena == NULL ) {
|
||||
/* XXX g_error */
|
||||
goto loser;
|
||||
}
|
||||
|
||||
collectArgs = e_cert_db_get_certs_from_package (arena, data, length);
|
||||
if (!collectArgs) {
|
||||
/* XXX g_error */
|
||||
goto loser;
|
||||
}
|
||||
|
||||
cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
|
||||
(char *)NULL, PR_FALSE, PR_TRUE);
|
||||
if (!cert) {
|
||||
/* XXX g_error */
|
||||
goto loser;
|
||||
}
|
||||
|
||||
slot = PK11_KeyForCertExists(cert, NULL, NULL);
|
||||
if ( slot == NULL ) {
|
||||
/* XXX g_error */
|
||||
goto loser;
|
||||
}
|
||||
PK11_FreeSlot(slot);
|
||||
|
||||
/* pick a nickname for the cert */
|
||||
if (cert->nickname) {
|
||||
/* sigh, we need a call to look up other certs with this subject and
|
||||
* identify nicknames from them. We can no longer walk down internal
|
||||
* database structures rjr */
|
||||
nickname = cert->nickname;
|
||||
}
|
||||
else {
|
||||
nickname = default_nickname(cert);
|
||||
}
|
||||
|
||||
/* user wants to import the cert */
|
||||
slot = PK11_ImportCertForKey(cert, nickname, NULL);
|
||||
if (!slot) {
|
||||
/* XXX g_error */
|
||||
goto loser;
|
||||
}
|
||||
PK11_FreeSlot(slot);
|
||||
numCACerts = collectArgs->numcerts - 1;
|
||||
|
||||
if (numCACerts) {
|
||||
CACerts = collectArgs->rawCerts+1;
|
||||
if ( ! CERT_ImportCAChain(CACerts, numCACerts, certUsageUserCertImport) ) {
|
||||
rv = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
loser:
|
||||
if (arena) {
|
||||
PORT_FreeArena(arena, PR_FALSE);
|
||||
}
|
||||
if ( cert ) {
|
||||
CERT_DestroyCertificate(cert);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -677,6 +877,9 @@ e_cert_db_import_server_cert (ECertDB *certdb,
|
||||
char *data, guint32 length,
|
||||
GError **error)
|
||||
{
|
||||
/* not c&p'ing this over at the moment, as we don't have a UI
|
||||
for server certs anyway */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
@ -55,10 +55,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <libgnome/gnome-i18n.h>
|
||||
#include <gal/util/e-util.h> /* for e_utf8_strftime, what about e_time_format_time? */
|
||||
|
||||
#include "e-cert.h"
|
||||
#include "e-cert-trust.h"
|
||||
#include "pk11func.h"
|
||||
#include "certdb.h"
|
||||
#include "hasht.h"
|
||||
|
||||
struct _ECertPrivate {
|
||||
CERTCertificate *cert;
|
||||
@ -66,8 +72,24 @@ struct _ECertPrivate {
|
||||
/* pointers we cache since the nss implementation allocs the
|
||||
string */
|
||||
char *org_name;
|
||||
char *org_unit_name;
|
||||
char *cn;
|
||||
|
||||
char *issuer_org_name;
|
||||
char *issuer_org_unit_name;
|
||||
char *issuer_cn;
|
||||
|
||||
PRTime issued_on;
|
||||
PRTime expires_on;
|
||||
|
||||
char *issued_on_string;
|
||||
char *expires_on_string;
|
||||
|
||||
char *serial_number;
|
||||
|
||||
char *sha1_fingerprint;
|
||||
char *md5_fingerprint;
|
||||
|
||||
gboolean delete;
|
||||
};
|
||||
|
||||
@ -84,9 +106,30 @@ e_cert_dispose (GObject *object)
|
||||
|
||||
if (ec->priv->org_name)
|
||||
PORT_Free (ec->priv->org_name);
|
||||
if (ec->priv->org_unit_name)
|
||||
PORT_Free (ec->priv->org_unit_name);
|
||||
if (ec->priv->cn)
|
||||
PORT_Free (ec->priv->cn);
|
||||
|
||||
if (ec->priv->issuer_org_name)
|
||||
PORT_Free (ec->priv->issuer_org_name);
|
||||
if (ec->priv->issuer_org_unit_name)
|
||||
PORT_Free (ec->priv->issuer_org_unit_name);
|
||||
if (ec->priv->issuer_cn)
|
||||
PORT_Free (ec->priv->issuer_cn);
|
||||
|
||||
if (ec->priv->issued_on_string)
|
||||
PORT_Free (ec->priv->issued_on_string);
|
||||
if (ec->priv->expires_on_string)
|
||||
PORT_Free (ec->priv->expires_on_string);
|
||||
if (ec->priv->serial_number)
|
||||
PORT_Free (ec->priv->serial_number);
|
||||
|
||||
if (ec->priv->sha1_fingerprint)
|
||||
PORT_Free (ec->priv->sha1_fingerprint);
|
||||
if (ec->priv->md5_fingerprint)
|
||||
PORT_Free (ec->priv->md5_fingerprint);
|
||||
|
||||
if (ec->priv->delete) {
|
||||
printf ("attempting to delete cert marked for deletion\n");
|
||||
if (e_cert_get_cert_type (ec) == E_CERT_USER) {
|
||||
@ -154,8 +197,61 @@ static void
|
||||
e_cert_populate (ECert *cert)
|
||||
{
|
||||
CERTCertificate *c = cert->priv->cert;
|
||||
unsigned char fingerprint[20];
|
||||
SECItem fpItem;
|
||||
|
||||
cert->priv->org_name = CERT_GetOrgName (&c->subject);
|
||||
cert->priv->org_unit_name = CERT_GetOrgUnitName (&c->subject);
|
||||
|
||||
cert->priv->issuer_org_name = CERT_GetOrgName (&c->issuer);
|
||||
cert->priv->issuer_org_unit_name = CERT_GetOrgUnitName (&c->issuer);
|
||||
|
||||
cert->priv->cn = CERT_GetCommonName (&c->subject);
|
||||
cert->priv->issuer_cn = CERT_GetCommonName (&c->issuer);
|
||||
|
||||
if (SECSuccess == CERT_GetCertTimes (c, &cert->priv->issued_on, &cert->priv->expires_on)) {
|
||||
PRExplodedTime explodedTime;
|
||||
struct tm exploded_tm;
|
||||
char buf[32];
|
||||
|
||||
PR_ExplodeTime (cert->priv->issued_on, PR_LocalTimeParameters, &explodedTime);
|
||||
exploded_tm.tm_sec = explodedTime.tm_sec;
|
||||
exploded_tm.tm_min = explodedTime.tm_min;
|
||||
exploded_tm.tm_hour = explodedTime.tm_hour;
|
||||
exploded_tm.tm_mday = explodedTime.tm_mday;
|
||||
exploded_tm.tm_mon = explodedTime.tm_month;
|
||||
exploded_tm.tm_year = explodedTime.tm_year - 1900;
|
||||
e_utf8_strftime (buf, sizeof(buf), _("%d/%m/%Y"), &exploded_tm);
|
||||
cert->priv->issued_on_string = g_strdup (buf);
|
||||
|
||||
PR_ExplodeTime (cert->priv->expires_on, PR_LocalTimeParameters, &explodedTime);
|
||||
exploded_tm.tm_sec = explodedTime.tm_sec;
|
||||
exploded_tm.tm_min = explodedTime.tm_min;
|
||||
exploded_tm.tm_hour = explodedTime.tm_hour;
|
||||
exploded_tm.tm_mday = explodedTime.tm_mday;
|
||||
exploded_tm.tm_mon = explodedTime.tm_month;
|
||||
exploded_tm.tm_year = explodedTime.tm_year - 1900;
|
||||
e_utf8_strftime (buf, sizeof(buf), _("%d/%m/%Y"), &exploded_tm);
|
||||
cert->priv->expires_on_string = g_strdup (buf);
|
||||
}
|
||||
|
||||
cert->priv->serial_number = CERT_Hexify (&cert->priv->cert->serialNumber, TRUE);
|
||||
|
||||
memset(fingerprint, 0, sizeof fingerprint);
|
||||
PK11_HashBuf(SEC_OID_SHA1, fingerprint,
|
||||
cert->priv->cert->derCert.data,
|
||||
cert->priv->cert->derCert.len);
|
||||
fpItem.data = fingerprint;
|
||||
fpItem.len = SHA1_LENGTH;
|
||||
cert->priv->sha1_fingerprint = CERT_Hexify (&fpItem, TRUE);
|
||||
|
||||
memset(fingerprint, 0, sizeof fingerprint);
|
||||
PK11_HashBuf(SEC_OID_MD5, fingerprint,
|
||||
cert->priv->cert->derCert.data,
|
||||
cert->priv->cert->derCert.len);
|
||||
fpItem.data = fingerprint;
|
||||
fpItem.len = MD5_LENGTH;
|
||||
cert->priv->md5_fingerprint = CERT_Hexify (&fpItem, TRUE);
|
||||
}
|
||||
|
||||
ECert*
|
||||
@ -229,6 +325,12 @@ e_cert_get_org (ECert *cert)
|
||||
return cert->priv->org_name;
|
||||
}
|
||||
|
||||
const char*
|
||||
e_cert_get_org_unit (ECert *cert)
|
||||
{
|
||||
return cert->priv->org_unit_name;
|
||||
}
|
||||
|
||||
const char*
|
||||
e_cert_get_cn (ECert *cert)
|
||||
{
|
||||
@ -241,12 +343,72 @@ e_cert_get_issuer_name (ECert *cert)
|
||||
return cert->priv->cert->issuerName;
|
||||
}
|
||||
|
||||
const char*
|
||||
e_cert_get_issuer_cn (ECert *cert)
|
||||
{
|
||||
return cert->priv->issuer_cn;
|
||||
}
|
||||
|
||||
const char*
|
||||
e_cert_get_issuer_org (ECert *cert)
|
||||
{
|
||||
return cert->priv->issuer_org_name;
|
||||
}
|
||||
|
||||
const char*
|
||||
e_cert_get_issuer_org_unit (ECert *cert)
|
||||
{
|
||||
return cert->priv->issuer_org_unit_name;
|
||||
}
|
||||
|
||||
const char*
|
||||
e_cert_get_subject_name (ECert *cert)
|
||||
{
|
||||
return cert->priv->cert->subjectName;
|
||||
}
|
||||
|
||||
PRTime
|
||||
e_cert_get_issued_on_time (ECert *cert)
|
||||
{
|
||||
return cert->priv->issued_on;
|
||||
}
|
||||
|
||||
const char*
|
||||
e_cert_get_issued_on (ECert *cert)
|
||||
{
|
||||
return cert->priv->issued_on_string;
|
||||
}
|
||||
|
||||
PRTime
|
||||
e_cert_get_expires_on_time (ECert *cert)
|
||||
{
|
||||
return cert->priv->expires_on;
|
||||
}
|
||||
|
||||
const char*
|
||||
e_cert_get_expires_on (ECert *cert)
|
||||
{
|
||||
return cert->priv->expires_on_string;
|
||||
}
|
||||
|
||||
const char*
|
||||
e_cert_get_serial_number (ECert *cert)
|
||||
{
|
||||
return cert->priv->serial_number;
|
||||
}
|
||||
|
||||
const char*
|
||||
e_cert_get_sha1_fingerprint (ECert *cert)
|
||||
{
|
||||
return cert->priv->sha1_fingerprint;
|
||||
}
|
||||
|
||||
const char*
|
||||
e_cert_get_md5_fingerprint (ECert *cert)
|
||||
{
|
||||
return cert->priv->md5_fingerprint;
|
||||
}
|
||||
|
||||
gboolean
|
||||
e_cert_mark_for_deletion (ECert *cert)
|
||||
{
|
||||
|
@ -73,9 +73,23 @@ gboolean e_cert_get_raw_der (ECert *cert, char **data, guint32
|
||||
const char* e_cert_get_nickname (ECert *cert);
|
||||
const char* e_cert_get_email (ECert *cert);
|
||||
const char* e_cert_get_org (ECert *cert);
|
||||
const char* e_cert_get_org_unit (ECert *cert);
|
||||
const char* e_cert_get_cn (ECert *cert);
|
||||
const char* e_cert_get_subject_name (ECert *cert);
|
||||
const char* e_cert_get_issuer_name (ECert *cert);
|
||||
|
||||
const char* e_cert_get_issuer_name (ECert *cert);
|
||||
const char* e_cert_get_issuer_cn (ECert *cert);
|
||||
const char* e_cert_get_issuer_org (ECert *cert);
|
||||
const char* e_cert_get_issuer_org_unit (ECert *cert);
|
||||
|
||||
PRTime e_cert_get_issued_on_time (ECert *cert);
|
||||
const char* e_cert_get_issued_on (ECert *cert);
|
||||
PRTime e_cert_get_expires_on_time (ECert *cert);
|
||||
const char* e_cert_get_expires_on (ECert *cert);
|
||||
|
||||
const char* e_cert_get_serial_number (ECert *cert);
|
||||
const char* e_cert_get_sha1_fingerprint (ECert *cert);
|
||||
const char* e_cert_get_md5_fingerprint (ECert *cert);
|
||||
|
||||
gboolean e_cert_mark_for_deletion (ECert *cert);
|
||||
|
||||
|
452
smime/lib/e-pkcs12.c
Normal file
452
smime/lib/e-pkcs12.c
Normal file
@ -0,0 +1,452 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/* e-pkcs12.c
|
||||
*
|
||||
* Copyright (C) 2003 Ximian, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Author: Chris Toshok (toshok@ximian.com)
|
||||
*/
|
||||
|
||||
/* The following is the mozilla license blurb, as the bodies some of
|
||||
these functions were derived from the mozilla source. */
|
||||
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <libgnome/gnome-i18n.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "e-util/e-passwords.h"
|
||||
#include "e-pkcs12.h"
|
||||
|
||||
#include "prmem.h"
|
||||
#include "nss.h"
|
||||
#include "pkcs12.h"
|
||||
#include "p12plcy.h"
|
||||
#include "pk11func.h"
|
||||
#include "secerr.h"
|
||||
|
||||
struct _EPKCS12Private {
|
||||
int tmp_fd;
|
||||
char *tmp_path;
|
||||
};
|
||||
|
||||
#define PARENT_TYPE G_TYPE_OBJECT
|
||||
static GObjectClass *parent_class;
|
||||
|
||||
// static callback functions for the NSS PKCS#12 library
|
||||
static SECItem * PR_CALLBACK nickname_collision(SECItem *, PRBool *, void *);
|
||||
static void PR_CALLBACK write_export_file(void *arg, const char *buf, unsigned long len);
|
||||
|
||||
static gboolean handle_error(int myerr);
|
||||
|
||||
#define PKCS12_TMPFILENAME ".p12tmp"
|
||||
#define PKCS12_BUFFER_SIZE 2048
|
||||
#define PKCS12_RESTORE_OK 1
|
||||
#define PKCS12_BACKUP_OK 2
|
||||
#define PKCS12_USER_CANCELED 3
|
||||
#define PKCS12_NOSMARTCARD_EXPORT 4
|
||||
#define PKCS12_RESTORE_FAILED 5
|
||||
#define PKCS12_BACKUP_FAILED 6
|
||||
#define PKCS12_NSS_ERROR 7
|
||||
|
||||
static void
|
||||
e_pkcs12_dispose (GObject *object)
|
||||
{
|
||||
EPKCS12 *pk = E_PKCS12 (object);
|
||||
|
||||
if (!pk->priv)
|
||||
return;
|
||||
|
||||
/* XXX free instance private foo */
|
||||
|
||||
g_free (pk->priv);
|
||||
pk->priv = NULL;
|
||||
|
||||
if (G_OBJECT_CLASS (parent_class)->dispose)
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
e_pkcs12_class_init (EPKCS12Class *klass)
|
||||
{
|
||||
GObjectClass *object_class;
|
||||
|
||||
object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
parent_class = g_type_class_ref (PARENT_TYPE);
|
||||
|
||||
object_class->dispose = e_pkcs12_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
e_pkcs12_init (EPKCS12 *ec)
|
||||
{
|
||||
ec->priv = g_new0 (EPKCS12Private, 1);
|
||||
}
|
||||
|
||||
GType
|
||||
e_pkcs12_get_type (void)
|
||||
{
|
||||
static GType pkcs12_type = 0;
|
||||
|
||||
if (!pkcs12_type) {
|
||||
static const GTypeInfo pkcs12_info = {
|
||||
sizeof (EPKCS12Class),
|
||||
NULL, /* base_init */
|
||||
NULL, /* base_finalize */
|
||||
(GClassInitFunc) e_pkcs12_class_init,
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof (EPKCS12),
|
||||
0, /* n_preallocs */
|
||||
(GInstanceInitFunc) e_pkcs12_init,
|
||||
};
|
||||
|
||||
pkcs12_type = g_type_register_static (PARENT_TYPE, "EPKCS12", &pkcs12_info, 0);
|
||||
}
|
||||
|
||||
return pkcs12_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
EPKCS12*
|
||||
e_pkcs12_new (void)
|
||||
{
|
||||
EPKCS12 *pk = E_PKCS12 (g_object_new (E_TYPE_PKCS12, NULL));
|
||||
|
||||
return pk;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
input_to_decoder (SEC_PKCS12DecoderContext *dcx, const char *path, GError **error)
|
||||
{
|
||||
/* nsNSSShutDownPreventionLock locker; */
|
||||
SECStatus srv;
|
||||
int amount;
|
||||
char buf[PKCS12_BUFFER_SIZE];
|
||||
FILE *fp;
|
||||
|
||||
/* open path */
|
||||
fp = fopen (path, "r");
|
||||
if (!fp) {
|
||||
/* XXX gerror */
|
||||
printf ("couldn't open `%s'\n", path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (TRUE) {
|
||||
amount = fread (buf, 1, sizeof (buf), fp);
|
||||
if (amount < 0) {
|
||||
printf ("got -1 fread\n");
|
||||
fclose (fp);
|
||||
return FALSE;
|
||||
}
|
||||
/* feed the file data into the decoder */
|
||||
srv = SEC_PKCS12DecoderUpdate(dcx,
|
||||
(unsigned char*) buf,
|
||||
amount);
|
||||
if (srv) {
|
||||
/* don't allow the close call to overwrite our precious error code */
|
||||
/* XXX g_error */
|
||||
int pr_err = PORT_GetError();
|
||||
PORT_SetError(pr_err);
|
||||
printf ("SEC_PKCS12DecoderUpdate returned %d\n", srv);
|
||||
fclose (fp);
|
||||
return FALSE;
|
||||
}
|
||||
if (amount < PKCS12_BUFFER_SIZE)
|
||||
break;
|
||||
}
|
||||
fclose (fp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
prompt_for_password (char *title, char *prompt, SECItem *pwd)
|
||||
{
|
||||
char *passwd;
|
||||
|
||||
passwd = e_passwords_ask_password (title, NULL, NULL, prompt, TRUE,
|
||||
E_PASSWORDS_DO_NOT_REMEMBER, NULL,
|
||||
NULL);
|
||||
|
||||
if (passwd) {
|
||||
SECITEM_AllocItem(NULL, pwd, PL_strlen (passwd));
|
||||
memcpy (pwd->data, passwd, strlen (passwd));
|
||||
g_free (passwd);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
import_from_file_helper (EPKCS12 *pkcs12, const char *path, gboolean *aWantRetry, GError **error)
|
||||
{
|
||||
/*nsNSSShutDownPreventionLock locker; */
|
||||
gboolean rv = TRUE;
|
||||
SECStatus srv = SECSuccess;
|
||||
SEC_PKCS12DecoderContext *dcx = NULL;
|
||||
SECItem passwd;
|
||||
GError *err = NULL;
|
||||
PK11SlotInfo *slot = PK11_GetInternalKeySlot (); /* XXX toshok - we
|
||||
hardcode this
|
||||
here */
|
||||
*aWantRetry = FALSE;
|
||||
|
||||
|
||||
passwd.data = NULL;
|
||||
rv = prompt_for_password (_("PKCS12 File Password"), _("Enter password for PKCS12 file:"), &passwd);
|
||||
if (!rv) goto finish;
|
||||
if (passwd.data == NULL) {
|
||||
handle_error (PKCS12_USER_CANCELED);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if notyet
|
||||
/* XXX we don't need this block as long as we hardcode the
|
||||
slot above */
|
||||
nsXPIDLString tokenName;
|
||||
nsXPIDLCString tokenNameCString;
|
||||
const char *tokNameRef;
|
||||
|
||||
|
||||
mToken->GetTokenName (getter_Copies(tokenName));
|
||||
tokenNameCString.Adopt (ToNewUTF8String(tokenName));
|
||||
tokNameRef = tokenNameCString; /* I do this here so that the
|
||||
NS_CONST_CAST below doesn't
|
||||
break the build on Win32 */
|
||||
|
||||
slot = PK11_FindSlotByName (NS_CONST_CAST(char*,tokNameRef));
|
||||
if (!slot) {
|
||||
srv = SECFailure;
|
||||
goto finish;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* initialize the decoder */
|
||||
dcx = SEC_PKCS12DecoderStart (&passwd, slot, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
pkcs12);
|
||||
if (!dcx) {
|
||||
srv = SECFailure;
|
||||
goto finish;
|
||||
}
|
||||
/* read input file and feed it to the decoder */
|
||||
rv = input_to_decoder (dcx, path, &err);
|
||||
if (!rv) {
|
||||
#if notyet
|
||||
/* XXX we need this to check the gerror */
|
||||
if (NS_ERROR_ABORT == rv) {
|
||||
// inputToDecoder indicated a NSS error
|
||||
srv = SECFailure;
|
||||
}
|
||||
#endif
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* verify the blob */
|
||||
srv = SEC_PKCS12DecoderVerify (dcx);
|
||||
if (srv) { printf ("decoderverify failed\n"); goto finish; }
|
||||
/* validate bags */
|
||||
srv = SEC_PKCS12DecoderValidateBags (dcx, nickname_collision);
|
||||
if (srv) { printf ("decodervalidatebags failed\n"); goto finish; }
|
||||
/* import cert and key */
|
||||
srv = SEC_PKCS12DecoderImportBags (dcx);
|
||||
if (srv) { printf ("decoderimportbags failed\n"); goto finish; }
|
||||
/* Later - check to see if this should become default email cert */
|
||||
handle_error (PKCS12_RESTORE_OK);
|
||||
finish:
|
||||
/* If srv != SECSuccess, NSS probably set a specific error code.
|
||||
We should use that error code instead of inventing a new one
|
||||
for every error possible. */
|
||||
if (srv != SECSuccess) {
|
||||
printf ("srv != SECSuccess\n");
|
||||
if (SEC_ERROR_BAD_PASSWORD == PORT_GetError()) {
|
||||
printf ("BAD PASSWORD\n");
|
||||
*aWantRetry = TRUE;
|
||||
}
|
||||
handle_error(PKCS12_NSS_ERROR);
|
||||
} else if (!rv) {
|
||||
handle_error(PKCS12_RESTORE_FAILED);
|
||||
}
|
||||
if (slot)
|
||||
PK11_FreeSlot(slot);
|
||||
// finish the decoder
|
||||
if (dcx)
|
||||
SEC_PKCS12DecoderFinish(dcx);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
e_pkcs12_import_from_file (EPKCS12 *pkcs12, const char *path, GError **error)
|
||||
{
|
||||
/*nsNSSShutDownPreventionLock locker;*/
|
||||
gboolean rv = TRUE;
|
||||
gboolean wantRetry;
|
||||
|
||||
|
||||
#if 0
|
||||
/* XXX we don't use tokens yet */
|
||||
if (!mToken) {
|
||||
if (!mTokenSet) {
|
||||
rv = SetToken(NULL); // Ask the user to pick a slot
|
||||
if (NS_FAILED(rv)) {
|
||||
handle_error(PKCS12_USER_CANCELED);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mToken) {
|
||||
handle_error(PKCS12_RESTORE_FAILED);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
/* init slot */
|
||||
rv = mToken->Login(PR_TRUE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
#endif
|
||||
|
||||
do {
|
||||
rv = import_from_file_helper (pkcs12, path, &wantRetry, error);
|
||||
} while (rv && wantRetry);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
gboolean
|
||||
e_pkcs12_export_to_file (EPKCS12 *pkcs12, const char *path, GList *certs, GError **error)
|
||||
{
|
||||
}
|
||||
|
||||
/* what to do when the nickname collides with one already in the db.
|
||||
TODO: not handled, throw a dialog allowing the nick to be changed? */
|
||||
static SECItem * PR_CALLBACK
|
||||
nickname_collision(SECItem *oldNick, PRBool *cancel, void *wincx)
|
||||
{
|
||||
/* nsNSSShutDownPreventionLock locker; */
|
||||
*cancel = PR_FALSE;
|
||||
int count = 1;
|
||||
char *nickname = NULL;
|
||||
char *default_nickname = _("Imported Certificate");
|
||||
SECItem *new_nick;
|
||||
|
||||
printf ("nickname_collision\n");
|
||||
|
||||
/* The user is trying to import a PKCS#12 file that doesn't have the
|
||||
attribute we use to set the nickname. So in order to reduce the
|
||||
number of interactions we require with the user, we'll build a nickname
|
||||
for the user. The nickname isn't prominently displayed in the UI,
|
||||
so it's OK if we generate one on our own here.
|
||||
XXX If the NSS API were smarter and actually passed a pointer to
|
||||
the CERTCertificate* we're importing we could actually just
|
||||
call default_nickname (which is what the issuance code path
|
||||
does) and come up with a reasonable nickname. Alas, the NSS
|
||||
API limits our ability to produce a useful nickname without
|
||||
bugging the user. :(
|
||||
*/
|
||||
while (1) {
|
||||
CERTCertificate *cert;
|
||||
|
||||
/* If we've gotten this far, that means there isn't a certificate
|
||||
in the database that has the same subject name as the cert we're
|
||||
trying to import. So we need to come up with a "nickname" to
|
||||
satisfy the NSS requirement or fail in trying to import.
|
||||
Basically we use a default nickname from a properties file and
|
||||
see if a certificate exists with that nickname. If there isn't, then
|
||||
create update the count by one and append the string '#1' Or
|
||||
whatever the count currently is, and look for a cert with
|
||||
that nickname. Keep updating the count until we find a nickname
|
||||
without a corresponding cert.
|
||||
XXX If a user imports *many* certs without the 'friendly name'
|
||||
attribute, then this may take a long time. :(
|
||||
*/
|
||||
if (count > 1) {
|
||||
g_free (nickname);
|
||||
nickname = g_strdup_printf ("%s #%d", default_nickname, count);
|
||||
} else {
|
||||
g_free (nickname);
|
||||
nickname = g_strdup (default_nickname);
|
||||
}
|
||||
cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(),
|
||||
nickname);
|
||||
if (!cert) {
|
||||
break;
|
||||
}
|
||||
CERT_DestroyCertificate(cert);
|
||||
count++;
|
||||
}
|
||||
|
||||
new_nick = PR_Malloc (sizeof (SECItem));
|
||||
new_nick->type = siAsciiString;
|
||||
new_nick->data = nickname;
|
||||
new_nick->len = strlen((char*)new_nick->data);
|
||||
return new_nick;
|
||||
}
|
||||
|
||||
/* write bytes to the exported PKCS#12 file */
|
||||
static void PR_CALLBACK
|
||||
write_export_file(void *arg, const char *buf, unsigned long len)
|
||||
{
|
||||
EPKCS12 *pkcs12 = E_PKCS12 (arg);
|
||||
EPKCS12Private *priv = pkcs12->priv;
|
||||
|
||||
printf ("write_export_file\n");
|
||||
|
||||
write (priv->tmp_fd, buf, len);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_error(int myerr)
|
||||
{
|
||||
printf ("handle_error (%d)\n", myerr);
|
||||
}
|
71
smime/lib/e-pkcs12.h
Normal file
71
smime/lib/e-pkcs12.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* Authors: Chris Toshok <toshok@ximian.com>
|
||||
*
|
||||
* Copyright (C) 2003 Ximian, Inc. (www.ximian.com)
|
||||
*
|
||||
* 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 of the License, 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 Street #330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _E_PKCS12_H_
|
||||
#define _E_PKCS12_H_
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#define E_TYPE_PKCS12 (e_pkcs12_get_type ())
|
||||
#define E_PKCS12(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_PKCS12, EPKCS12))
|
||||
#define E_PKCS12_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_PKCS12, EPKCS12Class))
|
||||
#define E_IS_PKCS12(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_PKCS12))
|
||||
#define E_IS_PKCS12_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_PKCS12))
|
||||
#define E_PKCS12_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_PKCS12, EPKCS12Class))
|
||||
|
||||
typedef struct _EPKCS12 EPKCS12;
|
||||
typedef struct _EPKCS12Class EPKCS12Class;
|
||||
typedef struct _EPKCS12Private EPKCS12Private;
|
||||
|
||||
struct _EPKCS12 {
|
||||
GObject parent;
|
||||
|
||||
EPKCS12Private *priv;
|
||||
};
|
||||
|
||||
struct _EPKCS12Class {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_epkcs12_reserved0) (void);
|
||||
void (*_epkcs12_reserved1) (void);
|
||||
void (*_epkcs12_reserved2) (void);
|
||||
void (*_epkcs12_reserved3) (void);
|
||||
void (*_epkcs12_reserved4) (void);
|
||||
};
|
||||
|
||||
GType e_pkcs12_get_type (void);
|
||||
|
||||
EPKCS12* e_pkcs12_new (void);
|
||||
|
||||
|
||||
#if 0
|
||||
/* XXX we're not going to support additional slots in the initial ssl
|
||||
stuff, so we just always default to the internal token (and thus
|
||||
don't need this function yet. */
|
||||
gboolean e_pkcs12_set_token (void);
|
||||
#endif
|
||||
|
||||
gboolean e_pkcs12_import_from_file (EPKCS12 *pkcs12, const char *path, GError **error);
|
||||
gboolean e_pkcs12_export_to_file (EPKCS12 *pkcs12, const char *path, GList *certs, GError **error);
|
||||
|
||||
#endif /* _E_CERT_H_ */
|
@ -3,12 +3,15 @@ noinst_PROGRAMS=import-cert
|
||||
|
||||
INCLUDES= \
|
||||
-I$(top_srcdir)/smime/lib \
|
||||
$(EVOLUTION_ADDRESSBOOK_CFLAGS) \
|
||||
$(CERT_UI_CFLAGS)
|
||||
|
||||
TEST_LIBS= \
|
||||
$(top_builddir)/smime/lib/libessmime.la \
|
||||
-L/home/toshok/src/mozilla/mozilla/dist/lib \
|
||||
$(CERT_UI_LIBS)
|
||||
$(top_builddir)/smime/lib/libessmime.la \
|
||||
-L/home/toshok/src/mozilla/mozilla/dist/lib \
|
||||
$(CERT_UI_LIBS) \
|
||||
$(top_builddir)/e-util/libeutil.la \
|
||||
$(GNOME_FULL_LIBS)
|
||||
|
||||
|
||||
import_cert_LDADD=$(TEST_LIBS)
|
@ -1,15 +1,17 @@
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <libgnomeui/gnome-ui-init.h>
|
||||
|
||||
#include "e-cert-db.h"
|
||||
#include "e-pkcs12.h"
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
ECertDB *db;
|
||||
EPKCS12 *pkcs12;
|
||||
|
||||
gnome_program_init ();
|
||||
|
||||
g_type_init ();
|
||||
gnome_program_init("import-cert-test", "0.0", LIBGNOMEUI_MODULE, argc, argv, NULL);
|
||||
|
||||
db = e_cert_db_peek ();
|
||||
|
||||
@ -25,5 +27,12 @@ main (int argc, char **argv)
|
||||
g_warning ("server cert import failed");
|
||||
}
|
||||
|
||||
pkcs12 = e_pkcs12_new ();
|
||||
if (!e_pkcs12_import_from_file (pkcs12, "newcert.p12", NULL /* XXX */)) {
|
||||
g_warning ("PKCS12 import failed");
|
||||
}
|
||||
|
||||
e_cert_db_shutdown ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user