diff options
-rw-r--r-- | smime/ChangeLog | 24 | ||||
-rw-r--r-- | smime/gui/certificate-manager.c | 6 | ||||
-rw-r--r-- | smime/gui/certificate-viewer.c | 127 | ||||
-rw-r--r-- | smime/gui/smime-ui.glade | 4 | ||||
-rw-r--r-- | smime/lib/Makefile.am | 2 | ||||
-rw-r--r-- | smime/lib/e-asn1-object.c | 369 | ||||
-rw-r--r-- | smime/lib/e-asn1-object.h | 81 | ||||
-rw-r--r-- | smime/lib/e-cert.c | 25 | ||||
-rw-r--r-- | smime/lib/e-cert.h | 2 |
9 files changed, 623 insertions, 17 deletions
diff --git a/smime/ChangeLog b/smime/ChangeLog index 243ad27657..7794f799f6 100644 --- a/smime/ChangeLog +++ b/smime/ChangeLog @@ -1,5 +1,29 @@ 2003-12-03 Chris Toshok <toshok@ximian.com> + * lib/Makefile.am (libessmime_la_SOURCES): add e-asn1-object.[ch] + + * gui/smime-ui.glade: rename the ca trust dialog, and give it a + proper id. + + * gui/certificate-manager.c (yourcerts_selection_changed): just + use @selection. + (contactcerts_selection_changed): same. + (authoritycerts_selection_changed): same. + + * gui/certificate-viewer.c (free_data): free the cert chain. + (fill_in_general): move all the general tab stuff here. + (hierarchy_selection_changed): new function. not finished. + (fields_selection_changed): new function, unimplemented. + (fill_in_details): new function, fill in the heirarchy and hook up + signals and stuff. + (certificate_viewer_show): call fill_in_general/fill_in_details. + + * lib/e-cert.c (e_cert_get_chain): new function. + + * lib/e-cert.h: add prototype for e_cert_get_chain. + +2003-12-03 Chris Toshok <toshok@ximian.com> + * lib/e-cert-db.c (e_cert_db_class_init): grovel around at startup time for mozilla's pkcs11 module so we can get the same default set of root certs. diff --git a/smime/gui/certificate-manager.c b/smime/gui/certificate-manager.c index 41caa775a5..d2ae5e4fea 100644 --- a/smime/gui/certificate-manager.c +++ b/smime/gui/certificate-manager.c @@ -139,7 +139,7 @@ import_your (GtkWidget *widget, CertificateManagerData *cfm) static void yourcerts_selection_changed (GtkTreeSelection *selection, CertificateManagerData *cfm) { - handle_selection_changed (gtk_tree_view_get_selection (GTK_TREE_VIEW(cfm->yourcerts_treeview)), + handle_selection_changed (selection, 4, cfm->view_your_button, cfm->backup_your_button, /* yes yes, not really "edit", it's a hack :) */ @@ -290,7 +290,7 @@ delete_contact (GtkWidget *widget, CertificateManagerData *cfm) static void contactcerts_selection_changed (GtkTreeSelection *selection, CertificateManagerData *cfm) { - handle_selection_changed (gtk_tree_view_get_selection (GTK_TREE_VIEW(cfm->contactcerts_treeview)), + handle_selection_changed (selection, 3, cfm->view_contact_button, cfm->edit_contact_button, @@ -447,7 +447,7 @@ delete_ca (GtkWidget *widget, CertificateManagerData *cfm) static void authoritycerts_selection_changed (GtkTreeSelection *selection, CertificateManagerData *cfm) { - handle_selection_changed (gtk_tree_view_get_selection (GTK_TREE_VIEW(cfm->authoritycerts_treeview)), + handle_selection_changed (selection, 1, cfm->view_ca_button, cfm->edit_ca_button, diff --git a/smime/gui/certificate-viewer.c b/smime/gui/certificate-viewer.c index 4a0bc3327d..9314ac5c1e 100644 --- a/smime/gui/certificate-viewer.c +++ b/smime/gui/certificate-viewer.c @@ -22,6 +22,8 @@ #include "certificate-viewer.h" +#include "e-asn1-object.h" + #include <gtk/gtk.h> #include <libgnome/gnome-i18n.h> @@ -32,6 +34,11 @@ typedef struct { GladeXML *gui; GtkWidget *dialog; + GtkTreeStore *hierarchy_store, *fields_store; + GtkWidget *hierarchy_tree, *fields_tree; + GtkWidget *field_text; + + GList *cert_chain; } CertificateViewerData; static void @@ -39,26 +46,20 @@ free_data (gpointer data, GObject *where_the_object_was) { CertificateViewerData *cvm = data; + g_list_foreach (cvm->cert_chain, (GFunc)g_object_unref, NULL); + g_list_free (cvm->cert_chain); + g_object_unref (cvm->gui); g_free (cvm); } - -GtkWidget* -certificate_viewer_show (ECert *cert) +static void +fill_in_general (CertificateViewerData *cvm_data, ECert *cert) { - CertificateViewerData *cvm_data; - CERTCertificate *mcert; + CERTCertificate *mcert = e_cert_get_internal_cert (cert); 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"); @@ -114,6 +115,108 @@ certificate_viewer_show (ECert *cert) 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); +} + +static void +hierarchy_selection_changed (GtkTreeSelection *selection, CertificateViewerData *cvm_data) +{ + GtkTreeIter iter; + GtkTreeModel *model; + + if (gtk_tree_selection_get_selected (selection, + &model, + &iter)) { + EASN1Object *asn1_object; + ECert *cert; + + gtk_tree_model_get (model, + &iter, + 1, &cert, + -1); + + if (!cert) + return; + + /* XXX show the selected fields somehow */ + asn1_object = e_asn1_object_new_from_cert (cert); + } +} + +static void +fields_selection_changed (GtkTreeSelection *selection, CertificateViewerData *cvm_data) +{ +} + +static void +fill_in_details (CertificateViewerData *cvm_data, ECert *cert) +{ + GList *l; + GtkTreeIter *root = NULL; + GtkTreeSelection *selection; + + /* hook up all the hierarchy tree foo */ + cvm_data->hierarchy_store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_OBJECT); + cvm_data->hierarchy_tree = glade_xml_get_widget (cvm_data->gui, "cert-hierarchy-treeview"); + gtk_tree_view_set_model (GTK_TREE_VIEW (cvm_data->hierarchy_tree), + GTK_TREE_MODEL (cvm_data->hierarchy_store)); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (cvm_data->hierarchy_tree), + -1, "Cert", gtk_cell_renderer_text_new(), + "text", 0, NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cvm_data->hierarchy_tree)); + g_signal_connect (selection, "changed", G_CALLBACK (hierarchy_selection_changed), cvm_data); + + /* hook up all the fields tree foo */ + cvm_data->fields_store = gtk_tree_store_new (1, G_TYPE_STRING); + cvm_data->fields_tree = glade_xml_get_widget (cvm_data->gui, "cert-fields-treeview"); + gtk_tree_view_set_model (GTK_TREE_VIEW (cvm_data->fields_tree), + GTK_TREE_MODEL (cvm_data->fields_store)); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (cvm_data->fields_tree), + -1, "Field", gtk_cell_renderer_text_new(), + "text", 0, NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cvm_data->fields_tree)); + g_signal_connect (selection, "changed", G_CALLBACK (fields_selection_changed), cvm_data); + + /* hook up all the field display foo */ + cvm_data->field_text = glade_xml_get_widget (cvm_data->gui, "cert-field-value-textview"); + + /* initially populate the hierarchy from the cert's chain */ + cvm_data->cert_chain = e_cert_get_chain (cert); + cvm_data->cert_chain = g_list_reverse (cvm_data->cert_chain); + for (l = cvm_data->cert_chain; l; l = l->next) { + ECert *c = l->data; + const char *str; + GtkTreeIter new_iter; + + str = e_cert_get_cn (c); + if (!str) + str = e_cert_get_subject_name (c); + + gtk_tree_store_insert (cvm_data->hierarchy_store, &new_iter, root, -1); + gtk_tree_store_set (cvm_data->hierarchy_store, &new_iter, + 0, str, + 1, c, + -1); + + root = &new_iter; + } +} + +GtkWidget* +certificate_viewer_show (ECert *cert) +{ + CertificateViewerData *cvm_data; + + 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"); + + fill_in_general (cvm_data, cert); + fill_in_details (cvm_data, cert); g_object_weak_ref (G_OBJECT (cvm_data->dialog), free_data, cvm_data); diff --git a/smime/gui/smime-ui.glade b/smime/gui/smime-ui.glade index 57475c1cbc..36966f7443 100644 --- a/smime/gui/smime-ui.glade +++ b/smime/gui/smime-ui.glade @@ -1759,8 +1759,8 @@ </child> </widget> -<widget class="GtkDialog" id="dialog1"> - <property name="title" translatable="yes">dialog1</property> +<widget class="GtkDialog" id="ca-trust-dialog"> + <property name="title" translatable="yes">Certificate Authority Trust</property> <property name="type">GTK_WINDOW_TOPLEVEL</property> <property name="window_position">GTK_WIN_POS_NONE</property> <property name="modal">False</property> diff --git a/smime/lib/Makefile.am b/smime/lib/Makefile.am index d7d5b11784..69c435fb1e 100644 --- a/smime/lib/Makefile.am +++ b/smime/lib/Makefile.am @@ -20,6 +20,8 @@ INCLUDES = \ noinst_LTLIBRARIES = libessmime.la libessmime_la_SOURCES = \ + e-asn1-object.c \ + e-asn1-object.h \ e-cert.c \ e-cert.h \ e-cert-trust.c \ diff --git a/smime/lib/e-asn1-object.c b/smime/lib/e-asn1-object.c new file mode 100644 index 0000000000..47cf591b48 --- /dev/null +++ b/smime/lib/e-asn1-object.c @@ -0,0 +1,369 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-cert.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 "e-asn1-object.h" + +#include "secasn1.h" + +struct _EASN1ObjectPrivate { + PRUint32 tag; + PRUint32 type; + gboolean valid_container; + + GList *children; + + char *display_name; + char *value; + + char *data; + guint data_len; +}; + +#define PARENT_TYPE G_TYPE_OBJECT +static GObjectClass *parent_class; + +static void +e_asn1_object_dispose (GObject *object) +{ +} + +static void +e_asn1_object_class_init (EASN1ObjectClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS(klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + object_class->dispose = e_asn1_object_dispose; +} + +static void +e_asn1_object_init (EASN1Object *asn1) +{ + asn1->priv = g_new0 (EASN1ObjectPrivate, 1); +} + +GType +e_asn1_object_get_type (void) +{ + static GType asn1_object_type = 0; + + if (!asn1_object_type) { + static const GTypeInfo asn1_object_info = { + sizeof (EASN1ObjectClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) e_asn1_object_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EASN1Object), + 0, /* n_preallocs */ + (GInstanceInitFunc) e_asn1_object_init, + }; + + asn1_object_type = g_type_register_static (PARENT_TYPE, "EASN1Object", &asn1_object_info, 0); + } + + return asn1_object_type; +} + + +/* This function is used to interpret an integer that + was encoded in a DER buffer. This function is used + when converting a DER buffer into a nsIASN1Object + structure. This interprets the buffer in data + as defined by the DER (Distinguised Encoding Rules) of + ASN1. +*/ +static int +get_integer_256 (unsigned char *data, unsigned int nb) +{ + int val; + + switch (nb) { + case 1: + val = data[0]; + break; + case 2: + val = (data[0] << 8) | data[1]; + break; + case 3: + val = (data[0] << 16) | (data[1] << 8) | data[2]; + break; + case 4: + val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + break; + default: + return -1; + } + + return val; +} + +/* This function is used to retrieve the lenght of a DER encoded + item. It looks to see if this a multibyte length and then + interprets the buffer accordingly to get the actual length value. + This funciton is used mostly while parsing the DER headers. + + A DER encoded item has the following structure: + + <tag><length<data consisting of lenght bytes> +*/ +static guint32 +get_der_item_length (unsigned char *data, unsigned char *end, + unsigned long *bytesUsed, gboolean *indefinite) +{ + unsigned char lbyte = *data++; + PRInt32 length = -1; + + *indefinite = FALSE; + if (lbyte >= 0x80) { + /* Multibyte length */ + unsigned nb = (unsigned) (lbyte & 0x7f); + if (nb > 4) { + return -1; + } + if (nb > 0) { + + if ((data+nb) > end) { + return -1; + } + length = get_integer_256 (data, nb); + if (length < 0) + return -1; + } else { + *indefinite = TRUE; + length = 0; + } + *bytesUsed = nb+1; + } else { + length = lbyte; + *bytesUsed = 1; + } + return length; +} + +static gboolean +build_from_der (EASN1Object *parent, char *data, char *end) +{ + unsigned long bytesUsed; + gboolean indefinite; + PRInt32 len; + PRUint32 type; + unsigned char code, tagnum; + EASN1Object *asn1object; + + if (data >= end) + return TRUE; + + /* + A DER item has the form of |tag|len|data + tag is one byte and describes the type of elment + we are dealing with. + len is a DER encoded int telling us how long the data is + data is a buffer that is len bytes long and has to be + interpreted according to its type. + */ + + while (data < end) { + code = *data; + tagnum = code & SEC_ASN1_TAGNUM_MASK; + + /* + * NOTE: This code does not (yet) handle the high-tag-number form! + */ + if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) { + return FALSE; + } + data++; + len = get_der_item_length (data, end, &bytesUsed, &indefinite); + data += bytesUsed; + if ((len < 0) || ((data+len) > end)) + return FALSE; + + if (code & SEC_ASN1_CONSTRUCTED) { + if (len > 0 || indefinite) { + switch (code & SEC_ASN1_CLASS_MASK) { + case SEC_ASN1_UNIVERSAL: + type = tagnum; + break; + case SEC_ASN1_APPLICATION: + type = E_ASN1_OBJECT_TYPE_APPLICATION; + break; + case SEC_ASN1_CONTEXT_SPECIFIC: + type = E_ASN1_OBJECT_TYPE_CONTEXT_SPECIFIC; + break; + case SEC_ASN1_PRIVATE: + type = E_ASN1_OBJECT_TYPE_PRIVATE; + break; + default: + g_warning ("bad DER"); + return FALSE; + } + + asn1object = e_asn1_object_new (); + asn1object->priv->tag = tagnum; + asn1object->priv->type = type; + + if (!build_from_der (asn1object, data, (len == 0) ? end : data + len)) { + g_object_unref (asn1object); + return FALSE; + } + } + } else { + asn1object = e_asn1_object_new (); + + asn1object->priv->type = tagnum; + asn1object->priv->tag = tagnum; + + /*printableItem->SetData((char*)data, len);*/ + } + data += len; + + parent->priv->children = g_list_append (parent->priv->children, asn1object); + } + + return TRUE; +} + +EASN1Object* +e_asn1_object_new_from_der (char *data, guint32 len) +{ + EASN1Object *obj = g_object_new (E_TYPE_ASN1_OBJECT, NULL); + + if (!build_from_der (obj, data, data + len)) { + g_object_unref (obj); + return NULL; + } + + return obj; +} + +EASN1Object* +e_asn1_object_new_from_cert (ECert *cert) +{ + char *data; + guint32 len; + EASN1Object *obj; + + if (!e_cert_get_raw_der (cert, &data, &len)) + return NULL; + + obj = g_object_new (E_TYPE_ASN1_OBJECT, NULL); + if (!build_from_der (obj, data, data + len)) { + g_object_unref (obj); + return NULL; + } + + return obj; +} + +EASN1Object* +e_asn1_object_new (void) +{ + return E_ASN1_OBJECT (g_object_new (E_TYPE_ASN1_OBJECT, NULL)); +} + + +gboolean +e_asn1_object_is_valid_container (EASN1Object *obj) +{ + return obj->priv->valid_container; +} + +PRUint32 +e_asn1_object_get_asn1_type (EASN1Object *obj) +{ + return obj->priv->type; +} + +PRUint32 +e_asn1_object_get_asn1_tag (EASN1Object *obj) +{ + return obj->priv->tag; +} + +GList* +e_asn1_object_get_children (EASN1Object *obj) +{ + GList *children = g_list_copy (obj->priv->children); + + g_list_foreach (children, (GFunc)g_object_ref, NULL); + + return children; +} + +const char* +e_asn1_object_get_display_name (EASN1Object *obj) +{ + return obj->priv->display_name; +} + +const char* +e_asn1_object_get_display_value (EASN1Object *obj) +{ + return obj->priv->value; +} + +void +e_asn1_object_get_data (EASN1Object *obj, char **data, guint32 *len) +{ + *data = obj->priv->data; + *len = obj->priv->data_len; +} diff --git a/smime/lib/e-asn1-object.h b/smime/lib/e-asn1-object.h new file mode 100644 index 0000000000..ebdb7de15e --- /dev/null +++ b/smime/lib/e-asn1-object.h @@ -0,0 +1,81 @@ +/* -*- 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_ASN1_OBJECT_H_ +#define _E_ASN1_OBJECT_H_ + +#include <glib-object.h> + +#include "e-cert.h" + +#include <nspr.h> + +#define E_TYPE_ASN1_OBJECT (e_asn1_object_get_type ()) +#define E_ASN1_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ASN1_OBJECT, EASN1Object)) +#define E_ASN1_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ASN1_OBJECT, EASN1ObjectClass)) +#define E_IS_ASN1_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ASN1_OBJECT)) +#define E_IS_ASN1_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_ASN1_OBJECT)) +#define E_ASN1_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_ASN1_OBJECT, EASN1ObjectClass)) + +typedef struct _EASN1Object EASN1Object; +typedef struct _EASN1ObjectClass EASN1ObjectClass; +typedef struct _EASN1ObjectPrivate EASN1ObjectPrivate; + +enum { + E_ASN1_OBJECT_TYPE_APPLICATION, + E_ASN1_OBJECT_TYPE_CONTEXT_SPECIFIC, + E_ASN1_OBJECT_TYPE_PRIVATE +}; + +struct _EASN1Object { + GObject parent; + + EASN1ObjectPrivate *priv; +}; + +struct _EASN1ObjectClass { + GObjectClass parent_class; + + /* Padding for future expansion */ + void (*_ecert_reserved0) (void); + void (*_ecert_reserved1) (void); + void (*_ecert_reserved2) (void); + void (*_ecert_reserved3) (void); + void (*_ecert_reserved4) (void); +}; + +EASN1Object *e_asn1_object_new_from_cert (ECert *cert); +EASN1Object *e_asn1_object_new_from_der (char *data, guint32 len); +EASN1Object *e_asn1_object_new (void); + +gboolean e_asn1_object_is_valid_container (EASN1Object *obj); +PRUint32 e_asn1_object_get_asn1_type (EASN1Object *obj); +PRUint32 e_asn1_object_get_asn1_tag (EASN1Object *obj); +GList *e_asn1_object_get_children (EASN1Object *obj); +const char *e_asn1_object_get_display_name (EASN1Object *obj); +const char *e_asn1_object_get_display_value (EASN1Object *obj); + +void e_asn1_object_get_data (EASN1Object *obj, char **data, guint32 *len); + +GType e_asn1_object_get_type (void); + +#endif /* _E_ASN1_OBJECT_H_ */ diff --git a/smime/lib/e-cert.c b/smime/lib/e-cert.c index a8fa5879c2..2389cc29c8 100644 --- a/smime/lib/e-cert.c +++ b/smime/lib/e-cert.c @@ -409,6 +409,31 @@ e_cert_get_md5_fingerprint (ECert *cert) return cert->priv->md5_fingerprint; } +GList* +e_cert_get_chain (ECert *ecert) +{ + GList *l = NULL; + + g_object_ref (ecert); + + while (ecert) { + CERTCertificate *cert = e_cert_get_internal_cert (ecert); + CERTCertificate *next_cert; + + l = g_list_append (l, ecert); + + if (SECITEM_CompareItem(&cert->derIssuer, &cert->derSubject) == SECEqual) + break; + + next_cert = CERT_FindCertIssuer (cert, PR_Now(), certUsageSSLClient); + if (!next_cert) + break; + ecert = e_cert_new (next_cert); + } + + return l; +} + gboolean e_cert_mark_for_deletion (ECert *cert) { diff --git a/smime/lib/e-cert.h b/smime/lib/e-cert.h index 4b5ec05a96..ac596b285b 100644 --- a/smime/lib/e-cert.h +++ b/smime/lib/e-cert.h @@ -91,6 +91,8 @@ 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); +GList* e_cert_get_chain (ECert *cert); + gboolean e_cert_mark_for_deletion (ECert *cert); ECertType e_cert_get_cert_type (ECert *cert); |