diff options
author | Milan Crha <mcrha@redhat.com> | 2012-12-12 02:48:07 +0800 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2012-12-12 02:48:07 +0800 |
commit | 8a1eb1f24e2a4624d78d3eeb4ab563d9e48ec865 (patch) | |
tree | a1bc41f9d06c7206fc4ba9a217b356966a99a569 /smime/lib | |
parent | c18043684137440e5853d5c952f89751148b6c24 (diff) | |
download | gsoc2013-evolution-8a1eb1f24e2a4624d78d3eeb4ab563d9e48ec865.tar gsoc2013-evolution-8a1eb1f24e2a4624d78d3eeb4ab563d9e48ec865.tar.gz gsoc2013-evolution-8a1eb1f24e2a4624d78d3eeb4ab563d9e48ec865.tar.bz2 gsoc2013-evolution-8a1eb1f24e2a4624d78d3eeb4ab563d9e48ec865.tar.lz gsoc2013-evolution-8a1eb1f24e2a4624d78d3eeb4ab563d9e48ec865.tar.xz gsoc2013-evolution-8a1eb1f24e2a4624d78d3eeb4ab563d9e48ec865.tar.zst gsoc2013-evolution-8a1eb1f24e2a4624d78d3eeb4ab563d9e48ec865.zip |
Use the same certificate-viewer as the trust-prompt from eds
This way it'll be possible to copy whole files if change in one
of them will be done. A real code reuse, rather than copy, would be
ideal, but the trust-prompt is just a module for evolution-user-prompter.
Diffstat (limited to 'smime/lib')
-rw-r--r-- | smime/lib/e-asn1-object.c | 916 | ||||
-rw-r--r-- | smime/lib/e-asn1-object.h | 45 | ||||
-rw-r--r-- | smime/lib/e-cert.c | 769 | ||||
-rw-r--r-- | smime/lib/e-cert.h | 2 |
4 files changed, 793 insertions, 939 deletions
diff --git a/smime/lib/e-asn1-object.c b/smime/lib/e-asn1-object.c index 53441516f5..7e5f27ca0c 100644 --- a/smime/lib/e-asn1-object.c +++ b/smime/lib/e-asn1-object.c @@ -39,13 +39,18 @@ * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif +#include <glib/gi18n.h> + #include "e-asn1-object.h" -#include "secasn1.h" +#include "pk11func.h" +#include "certdb.h" +#include "hasht.h" #define E_ASN1_OBJECT_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -67,220 +72,793 @@ struct _EASN1ObjectPrivate { G_DEFINE_TYPE (EASN1Object, e_asn1_object, G_TYPE_OBJECT) -static void -e_asn1_object_finalize (GObject *object) +static gboolean +get_int_value (SECItem *versionItem, + gulong *version) { - EASN1ObjectPrivate *priv; + SECStatus srv; + srv = SEC_ASN1DecodeInteger (versionItem,version); + if (srv != SECSuccess) { + g_warning ("could not decode version of cert"); + return FALSE; + } + return TRUE; +} - priv = E_ASN1_OBJECT_GET_PRIVATE (object); +static gboolean +process_version (SECItem *versionItem, + EASN1Object **retItem) +{ + EASN1Object *item = e_asn1_object_new (); + gulong version; - g_free (priv->display_name); - g_free (priv->value); + e_asn1_object_set_display_name (item, _("Version")); - g_list_free_full (priv->children, (GDestroyNotify) g_object_unref); + /* Now to figure out what version this certificate is. */ - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (e_asn1_object_parent_class)->finalize (object); + if (versionItem->data) { + if (!get_int_value (versionItem, &version)) + return FALSE; + } else { + /* If there is no version present in the cert, then rfc2459 + * says we default to v1 (0) */ + version = 0; + } + + switch (version) { + case 0: + e_asn1_object_set_display_value (item, _("Version 1")); + break; + case 1: + e_asn1_object_set_display_value (item, _("Version 2")); + break; + case 2: + e_asn1_object_set_display_value (item, _("Version 3")); + break; + default: + g_warning ("Bad value for cert version"); + return FALSE; + } + + *retItem = item; + return TRUE; } -static void -e_asn1_object_class_init (EASN1ObjectClass *class) +static gboolean +process_serial_number_der (SECItem *serialItem, + EASN1Object **retItem) { - GObjectClass *object_class; + gchar *serialNumber; + EASN1Object *item = e_asn1_object_new (); - g_type_class_add_private (class, sizeof (EASN1ObjectPrivate)); + e_asn1_object_set_display_name (item, _("Serial Number")); - object_class = G_OBJECT_CLASS (class); - object_class->finalize = e_asn1_object_finalize; + serialNumber = CERT_Hexify (serialItem, 1); + + e_asn1_object_set_display_value (item, serialNumber); + PORT_Free (serialNumber); /* XXX the right free to use? */ + + *retItem = item; + return TRUE; } -static void -e_asn1_object_init (EASN1Object *asn1) +static gboolean +get_default_oid_format (SECItem *oid, + gchar **text) { - asn1->priv = E_ASN1_OBJECT_GET_PRIVATE (asn1); - - asn1->priv->valid_container = TRUE; + GString *str; + gulong val = oid->data[0]; + guint ii = val % 40; + + val /= 40; + + str = g_string_new (""); + g_string_append_printf (str, "%lu %u ", val, ii); + + val = 0; + for (ii = 1; ii < oid->len; ii++) { + /* In this loop, we have to parse a DER formatted + * If the first bit is a 1, then the integer is + * represented by more than one byte. If the + * first bit is set then we continue on and add + * the values of the later bytes until we get + * a byte without the first bit set. + */ + gulong jj; + + jj = oid->data[ii]; + val = (val << 7) | (jj & 0x7f); + if (jj & 0x80) + continue; + g_string_append_printf (str, "%lu ", val); + + val = 0; + } + + *text = g_string_free (str, FALSE); + + return TRUE; } -/* 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 gint -get_integer_256 (guchar *data, - guint nb) +static gboolean +get_oid_text (SECItem *oid, + gchar **text) { - gint val; + SECOidTag oidTag = SECOID_FindOIDTag (oid); + gchar *temp; - switch (nb) { - case 1: - val = data[0]; + switch (oidTag) { + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 MD2 With RSA Encryption")); break; - case 2: - val = (data[0] << 8) | data[1]; + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 MD5 With RSA Encryption")); + break; + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 SHA-1 With RSA Encryption")); + break; + case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 SHA-256 With RSA Encryption")); + break; + case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 SHA-384 With RSA Encryption")); + break; + case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 SHA-512 With RSA Encryption")); + break; + case SEC_OID_AVA_COUNTRY_NAME: + *text = g_strdup ("C"); + break; + case SEC_OID_AVA_COMMON_NAME: + *text = g_strdup ("CN"); + break; + case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: + *text = g_strdup ("OU"); + break; + case SEC_OID_AVA_ORGANIZATION_NAME: + *text = g_strdup ("O"); + break; + case SEC_OID_AVA_LOCALITY: + *text = g_strdup ("L"); + break; + case SEC_OID_AVA_DN_QUALIFIER: + *text = g_strdup ("DN"); + break; + case SEC_OID_AVA_DC: + *text = g_strdup ("DC"); + break; + case SEC_OID_AVA_STATE_OR_PROVINCE: + *text = g_strdup ("ST"); + break; + case SEC_OID_PKCS1_RSA_ENCRYPTION: + *text = g_strdup (_("PKCS #1 RSA Encryption")); + break; + case SEC_OID_X509_KEY_USAGE: + *text = g_strdup (_("Certificate Key Usage")); break; - case 3: - val = (data[0] << 16) | (data[1] << 8) | data[2]; + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + *text = g_strdup (_("Netscape Certificate Type")); break; - case 4: - val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + case SEC_OID_X509_AUTH_KEY_ID: + *text = g_strdup (_("Certificate Authority Key Identifier")); + break; + case SEC_OID_RFC1274_UID: + *text = g_strdup ("UID"); + break; + case SEC_OID_PKCS9_EMAIL_ADDRESS: + *text = g_strdup ("E"); break; default: - return -1; - } + if (!get_default_oid_format (oid, &temp)) + return FALSE; - return val; + *text = g_strdup_printf (_("Object Identifier (%s)"), temp); + g_free (temp); + + break; + } + return TRUE; } -/* 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 (guchar *data, - guchar *end, - gulong *bytesUsed, - gboolean *indefinite) -{ - guchar lbyte = *data++; - PRInt32 length = -1; - - *indefinite = FALSE; - if (lbyte >= 0x80) { - /* Multibyte length */ - guint nb = (guint) (lbyte & 0x7f); - if (nb > 4) { - return -1; +static gboolean +process_raw_bytes (SECItem *data, + gchar **text) +{ + /* This function is used to display some DER bytes + * that we have not added support for decoding. + * It prints the value of the byte out into a + * string that can later be displayed as a byte + * string. We place a new line after 24 bytes + * to break up extermaly long sequence of bytes. + */ + GString *str = g_string_new (""); + PRUint32 i; + + for (i = 0; i < data->len; i++) { + g_string_append_printf (str, "%02x ", data->data[i]); + if ((i + 1) % 16 == 0) { + g_string_append (str, "\n"); } - if (nb > 0) { + } + *text = g_string_free (str, FALSE); + return TRUE; +} - 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; +static gboolean +process_sec_algorithm_id (SECAlgorithmID *algID, + EASN1Object **retSequence) +{ + EASN1Object *sequence = e_asn1_object_new (); + gchar *text = NULL; + + *retSequence = NULL; + + get_oid_text (&algID->algorithm, &text); + + if (!algID->parameters.len || + algID->parameters.data[0] == E_ASN1_OBJECT_TYPE_NULL) { + e_asn1_object_set_display_value (sequence, text); + e_asn1_object_set_valid_container (sequence, FALSE); } else { - length = lbyte; - *bytesUsed = 1; + EASN1Object *subitem; + + subitem = e_asn1_object_new (); + e_asn1_object_set_display_name (subitem, _("Algorithm Identifier")); + e_asn1_object_set_display_value (subitem, text); + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + + g_free (text); + + subitem = e_asn1_object_new (); + e_asn1_object_set_display_name (subitem, _("Algorithm Parameters")); + process_raw_bytes (&algID->parameters, &text); + e_asn1_object_set_display_value (subitem, text); + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); } - return length; + + g_free (text); + *retSequence = sequence; + return TRUE; } static gboolean -build_from_der (EASN1Object *parent, - gchar *data, - gchar *end) +process_subject_public_key_info (CERTSubjectPublicKeyInfo *spki, + EASN1Object *parentSequence) { - gulong bytesUsed; - gboolean indefinite; - PRInt32 len; - PRUint32 type; - guchar code, tagnum; - EASN1Object *asn1object = NULL; + EASN1Object *spkiSequence = e_asn1_object_new (); + EASN1Object *sequenceItem; + EASN1Object *printableItem; + SECItem data; + gchar *text = NULL; + + e_asn1_object_set_display_name (spkiSequence, _("Subject Public Key Info")); + + if (!process_sec_algorithm_id (&spki->algorithm, &sequenceItem)) + return FALSE; + + e_asn1_object_set_display_name (sequenceItem, _("Subject Public Key Algorithm")); + + e_asn1_object_append_child (spkiSequence, sequenceItem); - if (data >= end) + /* The subjectPublicKey field is encoded as a bit string. + * ProcessRawBytes expects the lenght to be in bytes, so + * let's convert the lenght into a temporary SECItem. + */ + data.data = spki->subjectPublicKey.data; + data.len = spki->subjectPublicKey.len / 8; + + process_raw_bytes (&data, &text); + printableItem = e_asn1_object_new (); + + e_asn1_object_set_display_value (printableItem, text); + e_asn1_object_set_display_name (printableItem, _("Subject's Public Key")); + e_asn1_object_append_child (spkiSequence, printableItem); + g_object_unref (printableItem); + g_free (text); + + e_asn1_object_append_child (parentSequence, spkiSequence); + g_object_unref (spkiSequence); + + return TRUE; +} + +static gboolean +process_ns_cert_type_extensions (SECItem *extData, + GString *text) +{ + SECItem decoded; + guchar nsCertType; + + decoded.data = NULL; + decoded.len = 0; + if (SECSuccess != SEC_ASN1DecodeItem (NULL, &decoded, + SEC_ASN1_GET (SEC_BitStringTemplate), extData)) { + g_string_append (text, _("Error: Unable to process extension")); 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 gint 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. - */ + nsCertType = decoded.data[0]; - while (data < end) { - code = *data; - tagnum = code & SEC_ASN1_TAGNUM_MASK; + PORT_Free (decoded.data); /* XXX right free? */ - /* - * NOTE: This code does not (yet) handle the high-tag-number form! - */ - if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) { - return FALSE; + if (nsCertType & NS_CERT_TYPE_SSL_CLIENT) { + g_string_append (text, _("SSL Client Certificate")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_SSL_SERVER) { + g_string_append (text, _("SSL Server Certificate")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_EMAIL) { + g_string_append (text, _("Email")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING) { + g_string_append (text, _("Object Signer")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_SSL_CA) { + g_string_append (text, _("SSL Certificate Authority")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_EMAIL_CA) { + g_string_append (text, _("Email Certificate Authority")); + g_string_append (text, "\n"); + } + if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING_CA) { + g_string_append (text, _("Object Signer")); + g_string_append (text, "\n"); + } + return TRUE; +} + +static gboolean +process_key_usage_extensions (SECItem *extData, + GString *text) +{ + SECItem decoded; + guchar keyUsage; + + decoded.data = NULL; + decoded.len = 0; + if (SECSuccess != SEC_ASN1DecodeItem (NULL, &decoded, + SEC_ASN1_GET (SEC_BitStringTemplate), extData)) { + g_string_append (text, _("Error: Unable to process extension")); + return TRUE; + } + + keyUsage = decoded.data[0]; + PORT_Free (decoded.data); /* XXX right free? */ + + if (keyUsage & KU_DIGITAL_SIGNATURE) { + g_string_append (text, _("Signing")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_NON_REPUDIATION) { + g_string_append (text, _("Non-repudiation")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_KEY_ENCIPHERMENT) { + g_string_append (text, _("Key Encipherment")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_DATA_ENCIPHERMENT) { + g_string_append (text, _("Data Encipherment")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_KEY_AGREEMENT) { + g_string_append (text, _("Key Agreement")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_KEY_CERT_SIGN) { + g_string_append (text, _("Certificate Signer")); + g_string_append (text, "\n"); + } + if (keyUsage & KU_CRL_SIGN) { + g_string_append (text, _("CRL Signer")); + g_string_append (text, "\n"); + } + + return TRUE; +} + +static gboolean +process_extension_data (SECOidTag oidTag, + SECItem *extData, + GString *str) +{ + gboolean rv; + switch (oidTag) { + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + rv = process_ns_cert_type_extensions (extData, str); + break; + case SEC_OID_X509_KEY_USAGE: + rv = process_key_usage_extensions (extData, str); + break; + default: { + gchar *text; + rv = process_raw_bytes (extData, &text); + g_string_append (str, text); + g_free (text); + break; + } + } + return rv; +} + +static gboolean +process_single_extension (CERTCertExtension *extension, + EASN1Object **retExtension) +{ + GString *str = g_string_new (""); + gchar *text; + EASN1Object *extensionItem; + SECOidTag oidTag = SECOID_FindOIDTag (&extension->id); + + get_oid_text (&extension->id, &text); + + extensionItem = e_asn1_object_new (); + + e_asn1_object_set_display_name (extensionItem, text); + g_free (text); + + if (extension->critical.data != NULL) { + if (extension->critical.data[0]) { + g_string_append (str, _("Critical")); + } else { + g_string_append (str, _("Not Critical")); } - data++; - len = get_der_item_length ( - (guchar *) data, (guchar *) end, - &bytesUsed, &indefinite); - data += bytesUsed; - if ((len < 0) || ((data + len) > end)) + } else { + g_string_append (str, _("Not Critical")); + } + g_string_append (str, "\n"); + if (!process_extension_data (oidTag, &extension->value, str)) { + g_string_free (str, TRUE); + return FALSE; + } + + e_asn1_object_set_display_value (extensionItem, str->str); + g_string_free (str, TRUE); + *retExtension = extensionItem; + return TRUE; +} + +static gboolean +process_extensions (CERTCertExtension **extensions, + EASN1Object *parentSequence) +{ + EASN1Object *extensionSequence = e_asn1_object_new (); + PRInt32 i; + + e_asn1_object_set_display_name (extensionSequence, _("Extensions")); + + for (i = 0; extensions[i] != NULL; i++) { + EASN1Object *newExtension; + + if (!process_single_extension (extensions[i], + &newExtension)) 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 (); + e_asn1_object_append_child (extensionSequence, newExtension); + } + e_asn1_object_append_child (parentSequence, extensionSequence); + return TRUE; +} - asn1object->priv->type = tagnum; - asn1object->priv->tag = tagnum; +static gboolean +process_name (CERTName *name, + gchar **value) +{ + CERTRDN ** rdns; + CERTRDN ** rdn; + CERTAVA ** avas; + CERTAVA * ava; + SECItem *decodeItem = NULL; + GString *final_string = g_string_new (""); + + gchar *type; + GString *avavalue; + gchar *temp; + CERTRDN **lastRdn; + + rdns = name->rdns; + + /* find last RDN */ + lastRdn = rdns; + while (*lastRdn) lastRdn++; + + /* The above whille loop will put us at the last member + * of the array which is a NULL pointer. So let's back + * up one spot so that we have the last non-NULL entry in + * the array in preparation for traversing the + * RDN's (Relative Distinguished Name) in reverse order. + */ + lastRdn--; - /*printableItem->SetData((gchar *)data, len);*/ + /* + * Loop over name contents in _reverse_ RDN order appending to string + * When building the Ascii string, NSS loops over these entries in + * reverse order, so I will as well. The difference is that NSS + * will always place them in a one line string separated by commas, + * where I want each entry on a single line. I can't just use a comma + * as my delimitter because it is a valid character to have in the + * value portion of the AVA and could cause trouble when parsing. + */ + for (rdn = lastRdn; rdn >= rdns; rdn--) { + avas = (*rdn)->avas; + while ((ava = *avas++) != 0) { + if (!get_oid_text (&ava->type, &type)) + return FALSE; + + /* This function returns a string in UTF8 format. */ + decodeItem = CERT_DecodeAVAValue (&ava->value); + if (!decodeItem) { + g_free (type); + return FALSE; + } + + avavalue = g_string_new_len ( + (gchar *) decodeItem->data, decodeItem->len); + + SECITEM_FreeItem (decodeItem, PR_TRUE); + + /* Translators: This string is used in Certificate + * details for fields like Issuer or Subject, which + * shows the field name on the left and its respective + * value on the right, both as stored in the + * certificate itself. You probably do not need to + * change this string, unless changing the order of + * name and value. As a result example: + * "OU = VeriSign Trust Network" */ + temp = g_strdup_printf (_("%s = %s"), type, avavalue->str); + + g_string_append (final_string, temp); + g_string_append (final_string, "\n"); + g_string_free (avavalue, TRUE); + g_free (temp); + g_free (type); } - data += len; + } + *value = g_string_free (final_string, FALSE); + return TRUE; +} + +static gboolean +create_tbs_certificate_asn1_struct (CERTCertificate *cert, + EASN1Object **seq) +{ + /* + ** TBSCertificate ::= SEQUENCE { + ** version [0] EXPLICIT Version DEFAULT v1, + ** serialNumber CertificateSerialNumber, + ** signature AlgorithmIdentifier, + ** issuer Name, + ** validity Validity, + ** subject Name, + ** subjectPublicKeyInfo SubjectPublicKeyInfo, + ** issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + ** -- If present, version shall be v2 or v3 + ** subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + ** -- If present, version shall be v2 or v3 + ** extensions [3] EXPLICIT Extensions OPTIONAL + ** -- If present, version shall be v3 + ** } + ** + ** This is the ASN1 structure we should be dealing with at this point. + ** The code in this method will assert this is the structure we're dealing + ** and then add more user friendly text for that field. + */ + EASN1Object *sequence = e_asn1_object_new (); + gchar *text; + EASN1Object *subitem; + SECItem data; + + e_asn1_object_set_display_name (sequence, _("Certificate")); + + if (!process_version (&cert->version, &subitem)) + return FALSE; + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + + if (!process_serial_number_der (&cert->serialNumber, &subitem)) + return FALSE; + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + + if (!process_sec_algorithm_id (&cert->signature, &subitem)) + return FALSE; + e_asn1_object_set_display_name (subitem, _("Certificate Signature Algorithm")); + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + + process_name (&cert->issuer, &text); + subitem = e_asn1_object_new (); + e_asn1_object_set_display_value (subitem, text); + g_free (text); + + e_asn1_object_set_display_name (subitem, _("Issuer")); + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + +#ifdef notyet + nsCOMPtr < nsIASN1Sequence> validitySequence = new nsNSSASN1Sequence (); + nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpValidity").get (), + text); + validitySequence->SetDisplayName (text); + asn1Objects->AppendElement (validitySequence, PR_FALSE); + nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpNotBefore").get (), + text); + nsCOMPtr < nsIX509CertValidity> validityData; + GetValidity (getter_AddRefs (validityData)); + PRTime notBefore, notAfter; + + validityData->GetNotBefore (¬Before); + validityData->GetNotAfter (¬After); + validityData = 0; + rv = ProcessTime (notBefore, text.get (), validitySequence); + if (NS_FAILED (rv)) + return rv; + + nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpNotAfter").get (), + text); + rv = ProcessTime (notAfter, text.get (), validitySequence); + if (NS_FAILED (rv)) + return rv; +#endif + + subitem = e_asn1_object_new (); + e_asn1_object_set_display_name (subitem, _("Subject")); + + process_name (&cert->subject, &text); + e_asn1_object_set_display_value (subitem, text); + g_free (text); + e_asn1_object_append_child (sequence, subitem); + g_object_unref (subitem); + + if (!process_subject_public_key_info (&cert->subjectPublicKeyInfo, sequence)) + return FALSE; + + /* Is there an issuerUniqueID? */ + if (cert->issuerID.data) { + /* The issuerID is encoded as a bit string. + * The function ProcessRawBytes expects the + * length to be in bytes, so let's convert the + * length in a temporary SECItem + */ + data.data = cert->issuerID.data; + data.len = cert->issuerID.len / 8; + + subitem = e_asn1_object_new (); + + e_asn1_object_set_display_name (subitem, _("Issuer Unique ID")); + process_raw_bytes (&data, &text); + e_asn1_object_set_display_value (subitem, text); + g_free (text); - parent->priv->children = g_list_append (parent->priv->children, asn1object); + e_asn1_object_append_child (sequence, subitem); } + if (cert->subjectID.data) { + /* The subjectID is encoded as a bit string. + * The function ProcessRawBytes expects the + * length to be in bytes, so let's convert the + * length in a temporary SECItem + */ + data.data = cert->issuerID.data; + data.len = cert->issuerID.len / 8; + + subitem = e_asn1_object_new (); + + e_asn1_object_set_display_name (subitem, _("Subject Unique ID")); + process_raw_bytes (&data, &text); + e_asn1_object_set_display_value (subitem, text); + g_free (text); + + e_asn1_object_append_child (sequence, subitem); + } + if (cert->extensions) { + if (!process_extensions (cert->extensions, sequence)) + return FALSE; + } + + *seq = sequence; + return TRUE; } -EASN1Object * -e_asn1_object_new_from_der (gchar *data, - guint32 len) +static gboolean +fill_asn1_from_cert (EASN1Object *asn1, + CERTCertificate *cert) { - EASN1Object *obj = g_object_new (E_TYPE_ASN1_OBJECT, NULL); + EASN1Object *sequence; + SECItem temp; + gchar *text; - if (!build_from_der (obj, data, data + len)) { - g_object_unref (obj); - return NULL; + g_return_val_if_fail (asn1 != NULL, FALSE); + g_return_val_if_fail (cert != NULL, FALSE); + + if (cert->nickname) { + e_asn1_object_set_display_name (asn1, cert->nickname); + } else { + gchar *str; + + str = CERT_GetCommonName (&cert->subject); + if (str) { + e_asn1_object_set_display_name (asn1, str); + PORT_Free (str); + } else { + e_asn1_object_set_display_name (asn1, cert->subjectName); + } } - return obj; + /* This sequence will be contain the tbsCertificate, signatureAlgorithm, + * and signatureValue. */ + + if (!create_tbs_certificate_asn1_struct (cert, &sequence)) + return FALSE; + e_asn1_object_append_child (asn1, sequence); + g_object_unref (sequence); + + if (!process_sec_algorithm_id (&cert->signatureWrap.signatureAlgorithm, &sequence)) + return FALSE; + e_asn1_object_set_display_name ( + sequence, _("Certificate Signature Algorithm")); + e_asn1_object_append_child (asn1, sequence); + g_object_unref (sequence); + + sequence = e_asn1_object_new (); + e_asn1_object_set_display_name ( + sequence, _("Certificate Signature Value")); + + /* The signatureWrap is encoded as a bit string. + * The function ProcessRawBytes expects the + * length to be in bytes, so let's convert the + * length in a temporary SECItem */ + temp.data = cert->signatureWrap.signature.data; + temp.len = cert->signatureWrap.signature.len / 8; + process_raw_bytes (&temp, &text); + e_asn1_object_set_display_value (sequence, text); + e_asn1_object_append_child (asn1, sequence); + g_free (text); + + return TRUE; +} + +static void +e_asn1_object_finalize (GObject *object) +{ + EASN1ObjectPrivate *priv; + + priv = E_ASN1_OBJECT_GET_PRIVATE (object); + + g_free (priv->display_name); + g_free (priv->value); + + g_list_free_full (priv->children, (GDestroyNotify) g_object_unref); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_asn1_object_parent_class)->finalize (object); +} + +static void +e_asn1_object_class_init (EASN1ObjectClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (EASN1ObjectPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = e_asn1_object_finalize; +} + +static void +e_asn1_object_init (EASN1Object *asn1) +{ + asn1->priv = E_ASN1_OBJECT_GET_PRIVATE (asn1); + + asn1->priv->valid_container = TRUE; } EASN1Object * @@ -289,6 +867,22 @@ e_asn1_object_new (void) return E_ASN1_OBJECT (g_object_new (E_TYPE_ASN1_OBJECT, NULL)); } +EASN1Object * +e_asn1_object_new_from_cert (CERTCertificate *cert) +{ + EASN1Object *asn1; + + g_return_val_if_fail (cert != NULL, NULL); + + asn1 = e_asn1_object_new (); + if (!fill_asn1_from_cert (asn1, cert)) { + g_object_unref (asn1); + return NULL; + } + + return asn1; +} + void e_asn1_object_set_valid_container (EASN1Object *obj, gboolean flag) diff --git a/smime/lib/e-asn1-object.h b/smime/lib/e-asn1-object.h index 35824967d4..39b79a7b1e 100644 --- a/smime/lib/e-asn1-object.h +++ b/smime/lib/e-asn1-object.h @@ -1,5 +1,4 @@ /* - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -18,15 +17,14 @@ * Chris Toshok <toshok@ximian.com> * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * */ -#ifndef _E_ASN1_OBJECT_H_ -#define _E_ASN1_OBJECT_H_ +#ifndef E_ASN1_OBJECT_H +#define E_ASN1_OBJECT_H #include <glib-object.h> -#include <nspr.h> +#include <cert.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)) @@ -85,22 +83,27 @@ struct _EASN1ObjectClass { void (*_ecert_reserved4) (void); }; -EASN1Object *e_asn1_object_new_from_der (gchar *data, guint32 len); -EASN1Object *e_asn1_object_new (void); - -void e_asn1_object_set_valid_container (EASN1Object *obj, gboolean flag); -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); -void e_asn1_object_append_child (EASN1Object *parent, EASN1Object *child); -void e_asn1_object_set_display_name (EASN1Object *obj, const gchar *name); -const gchar *e_asn1_object_get_display_name (EASN1Object *obj); -void e_asn1_object_set_display_value (EASN1Object *obj, const gchar *value); -const gchar *e_asn1_object_get_display_value (EASN1Object *obj); +GType e_asn1_object_get_type (void); +EASN1Object * e_asn1_object_new (void); +EASN1Object * e_asn1_object_new_from_cert (CERTCertificate *cert); -void e_asn1_object_get_data (EASN1Object *obj, gchar **data, guint32 *len); +void e_asn1_object_set_valid_container (EASN1Object *obj, + gboolean flag); +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); +void e_asn1_object_append_child (EASN1Object *parent, + EASN1Object *child); +void e_asn1_object_set_display_name (EASN1Object *obj, + const gchar *name); +const gchar * e_asn1_object_get_display_name (EASN1Object *obj); +void e_asn1_object_set_display_value (EASN1Object *obj, + const gchar *value); +const gchar * e_asn1_object_get_display_value (EASN1Object *obj); -GType e_asn1_object_get_type (void); +void e_asn1_object_get_data (EASN1Object *obj, + gchar **data, + guint32 *len); -#endif /* _E_ASN1_OBJECT_H_ */ +#endif /* E_ASN1_OBJECT_H */ diff --git a/smime/lib/e-cert.c b/smime/lib/e-cert.c index cd92062779..969b43c9ed 100644 --- a/smime/lib/e-cert.c +++ b/smime/lib/e-cert.c @@ -435,18 +435,14 @@ e_cert_get_md5_fingerprint (ECert *cert) } GList * -e_cert_get_chain (ECert *ecert) +e_cert_get_issuers_chain (ECert *ecert) { - GList *l = NULL; - - g_object_ref (ecert); + GList *issuers = NULL; 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; @@ -456,9 +452,14 @@ e_cert_get_chain (ECert *ecert) /* next_cert has a reference already */ ecert = e_cert_new (next_cert); + + if (ecert) { + /* the first is issuer of the original ecert */ + issuers = g_list_append (issuers, ecert); + } } - return l; + return issuers; } ECert * @@ -482,760 +483,16 @@ e_cert_get_ca_cert (ECert *ecert) return e_cert_new (cert); } -static gboolean -get_int_value (SECItem *versionItem, - gulong *version) -{ - SECStatus srv; - srv = SEC_ASN1DecodeInteger (versionItem,version); - if (srv != SECSuccess) { - g_warning ("could not decode version of cert"); - return FALSE; - } - return TRUE; -} - -static gboolean -process_version (SECItem *versionItem, - EASN1Object **retItem) -{ - EASN1Object *item = e_asn1_object_new (); - gulong version; - - e_asn1_object_set_display_name (item, _("Version")); - - /* Now to figure out what version this certificate is. */ - - if (versionItem->data) { - if (!get_int_value (versionItem, &version)) - return FALSE; - } else { - /* If there is no version present in the cert, then rfc2459 - * says we default to v1 (0) */ - version = 0; - } - - switch (version) { - case 0: - e_asn1_object_set_display_value (item, _("Version 1")); - break; - case 1: - e_asn1_object_set_display_value (item, _("Version 2")); - break; - case 2: - e_asn1_object_set_display_value (item, _("Version 3")); - break; - default: - g_warning ("Bad value for cert version"); - return FALSE; - } - - *retItem = item; - return TRUE; -} - -static gboolean -process_serial_number_der (SECItem *serialItem, - EASN1Object **retItem) -{ - gchar *serialNumber; - EASN1Object *item = e_asn1_object_new (); - - e_asn1_object_set_display_name (item, _("Serial Number")); - - serialNumber = CERT_Hexify (serialItem, 1); - - e_asn1_object_set_display_value (item, serialNumber); - PORT_Free (serialNumber); /* XXX the right free to use? */ - - *retItem = item; - return TRUE; -} - -static gboolean -get_default_oid_format (SECItem *oid, - gchar **text) -{ - gchar buf[300]; - guint len; - gint written; - - gulong val = oid->data[0]; - guint i = val % 40; - val /= 40; - written = PR_snprintf (buf, 300, "%lu %u ", val, i); - if (written < 0) - return FALSE; - len = written; - - val = 0; - for (i = 1; i < oid->len; ++i) { - /* In this loop, we have to parse a DER formatted - * If the first bit is a 1, then the integer is - * represented by more than one byte. If the - * first bit is set then we continue on and add - * the values of the later bytes until we get - * a byte without the first bit set. - */ - gulong j; - - j = oid->data[i]; - val = (val << 7) | (j & 0x7f); - if (j & 0x80) - continue; - written = PR_snprintf (&buf[len], sizeof (buf) - len, "%lu ", val); - if (written < 0) - return FALSE; - - len += written; - if (len >= sizeof (buf)) - g_warning ("OID data to big to display in 300 chars."); - val = 0; - } - - *text = g_strdup (buf); - return TRUE; -} - -static gboolean -get_oid_text (SECItem *oid, - gchar **text) -{ - SECOidTag oidTag = SECOID_FindOIDTag (oid); - gchar *temp; - - switch (oidTag) { - case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 MD2 With RSA Encryption")); - break; - case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 MD5 With RSA Encryption")); - break; - case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 SHA-1 With RSA Encryption")); - break; - case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 SHA-256 With RSA Encryption")); - break; - case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 SHA-384 With RSA Encryption")); - break; - case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 SHA-512 With RSA Encryption")); - break; - case SEC_OID_AVA_COUNTRY_NAME: - *text = g_strdup ("C"); - break; - case SEC_OID_AVA_COMMON_NAME: - *text = g_strdup ("CN"); - break; - case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: - *text = g_strdup ("OU"); - break; - case SEC_OID_AVA_ORGANIZATION_NAME: - *text = g_strdup ("O"); - break; - case SEC_OID_AVA_LOCALITY: - *text = g_strdup ("L"); - break; - case SEC_OID_AVA_DN_QUALIFIER: - *text = g_strdup ("DN"); - break; - case SEC_OID_AVA_DC: - *text = g_strdup ("DC"); - break; - case SEC_OID_AVA_STATE_OR_PROVINCE: - *text = g_strdup ("ST"); - break; - case SEC_OID_PKCS1_RSA_ENCRYPTION: - *text = g_strdup (_("PKCS #1 RSA Encryption")); - break; - case SEC_OID_X509_KEY_USAGE: - *text = g_strdup (_("Certificate Key Usage")); - break; - case SEC_OID_NS_CERT_EXT_CERT_TYPE: - *text = g_strdup (_("Netscape Certificate Type")); - break; - case SEC_OID_X509_AUTH_KEY_ID: - *text = g_strdup (_("Certificate Authority Key Identifier")); - break; - case SEC_OID_RFC1274_UID: - *text = g_strdup ("UID"); - break; - case SEC_OID_PKCS9_EMAIL_ADDRESS: - *text = g_strdup ("E"); - break; - default: - if (!get_default_oid_format (oid, &temp)) - return FALSE; - - *text = g_strdup_printf (_("Object Identifier (%s)"), temp); - g_free (temp); - - break; - } - return TRUE; -} - -static gboolean -process_raw_bytes (SECItem *data, - gchar **text) -{ - /* This function is used to display some DER bytes - * that we have not added support for decoding. - * It prints the value of the byte out into a - * string that can later be displayed as a byte - * string. We place a new line after 24 bytes - * to break up extermaly long sequence of bytes. - */ - GString *str = g_string_new (""); - PRUint32 i; - gchar buffer[5]; - for (i = 0; i < data->len; i++) { - PR_snprintf (buffer, 5, "%02x ", data->data[i]); - g_string_append (str, buffer); - if ((i + 1) % 16 == 0) { - g_string_append (str, "\n"); - } - } - *text = g_string_free (str, FALSE); - return TRUE; -} - -static gboolean -process_sec_algorithm_id (SECAlgorithmID *algID, - EASN1Object **retSequence) -{ - EASN1Object *sequence = e_asn1_object_new (); - gchar *text; - - *retSequence = NULL; - - get_oid_text (&algID->algorithm, &text); - - if (!algID->parameters.len || - algID->parameters.data[0] == E_ASN1_OBJECT_TYPE_NULL) { - e_asn1_object_set_display_value (sequence, text); - e_asn1_object_set_valid_container (sequence, FALSE); - } else { - EASN1Object *subitem; - - subitem = e_asn1_object_new (); - e_asn1_object_set_display_name (subitem, _("Algorithm Identifier")); - e_asn1_object_set_display_value (subitem, text); - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - - g_free (text); - - subitem = e_asn1_object_new (); - e_asn1_object_set_display_name (subitem, _("Algorithm Parameters")); - process_raw_bytes (&algID->parameters, &text); - e_asn1_object_set_display_value (subitem, text); - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - } - - g_free (text); - *retSequence = sequence; - return TRUE; -} - -static gboolean -process_subject_public_key_info (CERTSubjectPublicKeyInfo *spki, - EASN1Object *parentSequence) -{ - EASN1Object *spkiSequence = e_asn1_object_new (); - EASN1Object *sequenceItem; - EASN1Object *printableItem; - SECItem data; - gchar *text; - - e_asn1_object_set_display_name (spkiSequence, _("Subject Public Key Info")); - - if (!process_sec_algorithm_id (&spki->algorithm, &sequenceItem)) - return FALSE; - - e_asn1_object_set_display_name (sequenceItem, _("Subject Public Key Algorithm")); - - e_asn1_object_append_child (spkiSequence, sequenceItem); - - /* The subjectPublicKey field is encoded as a bit string. - * ProcessRawBytes expects the lenght to be in bytes, so - * let's convert the lenght into a temporary SECItem. - */ - data.data = spki->subjectPublicKey.data; - data.len = spki->subjectPublicKey.len / 8; - - process_raw_bytes (&data, &text); - printableItem = e_asn1_object_new (); - - e_asn1_object_set_display_value (printableItem, text); - e_asn1_object_set_display_name (printableItem, _("Subject's Public Key")); - e_asn1_object_append_child (spkiSequence, printableItem); - g_object_unref (printableItem); - - e_asn1_object_append_child (parentSequence, spkiSequence); - g_object_unref (spkiSequence); - - return TRUE; -} - -static gboolean -process_ns_cert_type_extensions (SECItem *extData, - GString *text) -{ - SECItem decoded; - guchar nsCertType; - - decoded.data = NULL; - decoded.len = 0; - if (SECSuccess != SEC_ASN1DecodeItem (NULL, &decoded, - SEC_ASN1_GET (SEC_BitStringTemplate), extData)) { - g_string_append (text, _("Error: Unable to process extension")); - return TRUE; - } - - nsCertType = decoded.data[0]; - - PORT_Free (decoded.data); /* XXX right free? */ - - if (nsCertType & NS_CERT_TYPE_SSL_CLIENT) { - g_string_append (text, _("SSL Client Certificate")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_SSL_SERVER) { - g_string_append (text, _("SSL Server Certificate")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_EMAIL) { - g_string_append (text, _("Email")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING) { - g_string_append (text, _("Object Signer")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_SSL_CA) { - g_string_append (text, _("SSL Certificate Authority")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_EMAIL_CA) { - g_string_append (text, _("Email Certificate Authority")); - g_string_append (text, "\n"); - } - if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING_CA) { - g_string_append (text, _("Object Signer")); - g_string_append (text, "\n"); - } - return TRUE; -} - -static gboolean -process_key_usage_extensions (SECItem *extData, - GString *text) -{ - SECItem decoded; - guchar keyUsage; - - decoded.data = NULL; - decoded.len = 0; - if (SECSuccess != SEC_ASN1DecodeItem (NULL, &decoded, - SEC_ASN1_GET (SEC_BitStringTemplate), extData)) { - g_string_append (text, _("Error: Unable to process extension")); - return TRUE; - } - - keyUsage = decoded.data[0]; - PORT_Free (decoded.data); /* XXX right free? */ - - if (keyUsage & KU_DIGITAL_SIGNATURE) { - g_string_append (text, _("Signing")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_NON_REPUDIATION) { - g_string_append (text, _("Non-repudiation")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_KEY_ENCIPHERMENT) { - g_string_append (text, _("Key Encipherment")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_DATA_ENCIPHERMENT) { - g_string_append (text, _("Data Encipherment")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_KEY_AGREEMENT) { - g_string_append (text, _("Key Agreement")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_KEY_CERT_SIGN) { - g_string_append (text, _("Certificate Signer")); - g_string_append (text, "\n"); - } - if (keyUsage & KU_CRL_SIGN) { - g_string_append (text, _("CRL Signer")); - g_string_append (text, "\n"); - } - - return TRUE; -} - -static gboolean -process_extension_data (SECOidTag oidTag, - SECItem *extData, - GString *str) -{ - gboolean rv; - switch (oidTag) { - case SEC_OID_NS_CERT_EXT_CERT_TYPE: - rv = process_ns_cert_type_extensions (extData, str); - break; - case SEC_OID_X509_KEY_USAGE: - rv = process_key_usage_extensions (extData, str); - break; - default: { - gchar *text; - rv = process_raw_bytes (extData, &text); - g_string_append (str, text); - g_free (text); - break; - } - } - return rv; -} - -static gboolean -process_single_extension (CERTCertExtension *extension, - EASN1Object **retExtension) -{ - GString *str = g_string_new (""); - gchar *text; - EASN1Object *extensionItem; - SECOidTag oidTag = SECOID_FindOIDTag (&extension->id); - - get_oid_text (&extension->id, &text); - - extensionItem = e_asn1_object_new (); - - e_asn1_object_set_display_name (extensionItem, text); - g_free (text); - - if (extension->critical.data != NULL) { - if (extension->critical.data[0]) { - g_string_append (str, _("Critical")); - } else { - g_string_append (str, _("Not Critical")); - } - } else { - g_string_append (str, _("Not Critical")); - } - g_string_append (str, "\n"); - if (!process_extension_data (oidTag, &extension->value, str)) { - g_string_free (str, TRUE); - return FALSE; - } - - e_asn1_object_set_display_value (extensionItem, str->str); - g_string_free (str, TRUE); - *retExtension = extensionItem; - return TRUE; -} - -static gboolean -process_extensions (CERTCertExtension **extensions, - EASN1Object *parentSequence) -{ - EASN1Object *extensionSequence = e_asn1_object_new (); - PRInt32 i; - - e_asn1_object_set_display_name (extensionSequence, _("Extensions")); - - for (i = 0; extensions[i] != NULL; i++) { - EASN1Object *newExtension; - - if (!process_single_extension (extensions[i], - &newExtension)) - return FALSE; - - e_asn1_object_append_child (extensionSequence, newExtension); - } - e_asn1_object_append_child (parentSequence, extensionSequence); - return TRUE; -} - -static gboolean -process_name (CERTName *name, - gchar **value) -{ - CERTRDN ** rdns; - CERTRDN ** rdn; - CERTAVA ** avas; - CERTAVA * ava; - SECItem *decodeItem = NULL; - GString *final_string = g_string_new (""); - - gchar *type; - GString *avavalue; - gchar *temp; - CERTRDN **lastRdn; - - rdns = name->rdns; - - /* find last RDN */ - lastRdn = rdns; - while (*lastRdn) lastRdn++; - - /* The above whille loop will put us at the last member - * of the array which is a NULL pointer. So let's back - * up one spot so that we have the last non-NULL entry in - * the array in preparation for traversing the - * RDN's (Relative Distinguished Name) in reverse order. - */ - lastRdn--; - - /* - * Loop over name contents in _reverse_ RDN order appending to string - * When building the Ascii string, NSS loops over these entries in - * reverse order, so I will as well. The difference is that NSS - * will always place them in a one line string separated by commas, - * where I want each entry on a single line. I can't just use a comma - * as my delimitter because it is a valid character to have in the - * value portion of the AVA and could cause trouble when parsing. - */ - for (rdn = lastRdn; rdn >= rdns; rdn--) { - avas = (*rdn)->avas; - while ((ava = *avas++) != 0) { - if (!get_oid_text (&ava->type, &type)) - return FALSE; - - /* This function returns a string in UTF8 format. */ - decodeItem = CERT_DecodeAVAValue (&ava->value); - if (!decodeItem) { - return FALSE; - } - - avavalue = g_string_new_len ( - (gchar *) decodeItem->data, decodeItem->len); - - SECITEM_FreeItem (decodeItem, PR_TRUE); - - /* Translators: This string is used in Certificate - * details for fields like Issuer or Subject, which - * shows the field name on the left and its respective - * value on the right, both as stored in the - * certificate itself. You probably do not need to - * change this string, unless changing the order of - * name and value. As a result example: - * "OU = VeriSign Trust Network" */ - temp = g_strdup_printf (_("%s = %s"), type, avavalue->str); - - g_string_append (final_string, temp); - g_string_append (final_string, "\n"); - g_string_free (avavalue, TRUE); - g_free (temp); - } - } - *value = g_string_free (final_string, FALSE); - return TRUE; -} - -static gboolean -create_tbs_certificate_asn1_struct (ECert *cert, - EASN1Object **seq) -{ - /* - ** TBSCertificate ::= SEQUENCE { - ** version [0] EXPLICIT Version DEFAULT v1, - ** serialNumber CertificateSerialNumber, - ** signature AlgorithmIdentifier, - ** issuer Name, - ** validity Validity, - ** subject Name, - ** subjectPublicKeyInfo SubjectPublicKeyInfo, - ** issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, - ** -- If present, version shall be v2 or v3 - ** subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, - ** -- If present, version shall be v2 or v3 - ** extensions [3] EXPLICIT Extensions OPTIONAL - ** -- If present, version shall be v3 - ** } - ** - ** This is the ASN1 structure we should be dealing with at this point. - ** The code in this method will assert this is the structure we're dealing - ** and then add more user friendly text for that field. - */ - EASN1Object *sequence = e_asn1_object_new (); - gchar *text; - EASN1Object *subitem; - SECItem data; - - e_asn1_object_set_display_name (sequence, _("Certificate")); - - if (!process_version (&cert->priv->cert->version, &subitem)) - return FALSE; - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - - if (!process_serial_number_der (&cert->priv->cert->serialNumber, &subitem)) - return FALSE; - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - - if (!process_sec_algorithm_id (&cert->priv->cert->signature, &subitem)) - return FALSE; - e_asn1_object_set_display_name (subitem, _("Certificate Signature Algorithm")); - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - - process_name (&cert->priv->cert->issuer, &text); - subitem = e_asn1_object_new (); - e_asn1_object_set_display_value (subitem, text); - g_free (text); - - e_asn1_object_set_display_name (subitem, _("Issuer")); - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - -#ifdef notyet - nsCOMPtr < nsIASN1Sequence> validitySequence = new nsNSSASN1Sequence (); - nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpValidity").get (), - text); - validitySequence->SetDisplayName (text); - asn1Objects->AppendElement (validitySequence, PR_FALSE); - nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpNotBefore").get (), - text); - nsCOMPtr < nsIX509CertValidity> validityData; - GetValidity (getter_AddRefs (validityData)); - PRTime notBefore, notAfter; - - validityData->GetNotBefore (¬Before); - validityData->GetNotAfter (¬After); - validityData = 0; - rv = ProcessTime (notBefore, text.get (), validitySequence); - if (NS_FAILED (rv)) - return rv; - - nssComponent->GetPIPNSSBundleString (NS_LITERAL_STRING ("CertDumpNotAfter").get (), - text); - rv = ProcessTime (notAfter, text.get (), validitySequence); - if (NS_FAILED (rv)) - return rv; -#endif - - subitem = e_asn1_object_new (); - e_asn1_object_set_display_name (subitem, _("Subject")); - - process_name (&cert->priv->cert->subject, &text); - e_asn1_object_set_display_value (subitem, text); - g_free (text); - e_asn1_object_append_child (sequence, subitem); - g_object_unref (subitem); - - if (!process_subject_public_key_info ( - &cert->priv->cert->subjectPublicKeyInfo, sequence)) - return FALSE; - - /* Is there an issuerUniqueID? */ - if (cert->priv->cert->issuerID.data) { - /* The issuerID is encoded as a bit string. - * The function ProcessRawBytes expects the - * length to be in bytes, so let's convert the - * length in a temporary SECItem - */ - data.data = cert->priv->cert->issuerID.data; - data.len = cert->priv->cert->issuerID.len / 8; - - subitem = e_asn1_object_new (); - - e_asn1_object_set_display_name (subitem, _("Issuer Unique ID")); - process_raw_bytes (&data, &text); - e_asn1_object_set_display_value (subitem, text); - g_free (text); - - e_asn1_object_append_child (sequence, subitem); - } - - if (cert->priv->cert->subjectID.data) { - /* The subjectID is encoded as a bit string. - * The function ProcessRawBytes expects the - * length to be in bytes, so let's convert the - * length in a temporary SECItem - */ - data.data = cert->priv->cert->issuerID.data; - data.len = cert->priv->cert->issuerID.len / 8; - - subitem = e_asn1_object_new (); - - e_asn1_object_set_display_name (subitem, _("Subject Unique ID")); - process_raw_bytes (&data, &text); - e_asn1_object_set_display_value (subitem, text); - g_free (text); - - e_asn1_object_append_child (sequence, subitem); - } - if (cert->priv->cert->extensions) { - if (!process_extensions (cert->priv->cert->extensions, sequence)) - return FALSE; - } - - *seq = sequence; - - return TRUE; -} - -static gboolean -create_asn1_struct (ECert *cert) -{ - EASN1Object *sequence; - SECItem temp; - gchar *text; - - cert->priv->asn1 = e_asn1_object_new (); - - e_asn1_object_set_display_name (cert->priv->asn1, e_cert_get_window_title (cert)); - - /* This sequence will be contain the tbsCertificate, signatureAlgorithm, - * and signatureValue. */ - - if (!create_tbs_certificate_asn1_struct (cert, &sequence)) - return FALSE; - e_asn1_object_append_child (cert->priv->asn1, sequence); - g_object_unref (sequence); - - if (!process_sec_algorithm_id ( - &cert->priv->cert->signatureWrap.signatureAlgorithm, &sequence)) - return FALSE; - e_asn1_object_set_display_name ( - sequence, _("Certificate Signature Algorithm")); - e_asn1_object_append_child (cert->priv->asn1, sequence); - g_object_unref (sequence); - - sequence = e_asn1_object_new (); - e_asn1_object_set_display_name ( - sequence, _("Certificate Signature Value")); - - /* The signatureWrap is encoded as a bit string. - * The function ProcessRawBytes expects the - * length to be in bytes, so let's convert the - * length in a temporary SECItem */ - temp.data = cert->priv->cert->signatureWrap.signature.data; - temp.len = cert->priv->cert->signatureWrap.signature.len / 8; - process_raw_bytes (&temp, &text); - e_asn1_object_set_display_value (sequence, text); - e_asn1_object_append_child (cert->priv->asn1, sequence); - g_free (text); - - return TRUE; -} - EASN1Object * e_cert_get_asn1_struct (ECert *cert) { if (!cert->priv->asn1) - create_asn1_struct (cert); + cert->priv->asn1 = e_asn1_object_new_from_cert (cert->priv->cert); + + if (cert->priv->asn1) + return g_object_ref (cert->priv->asn1); - return g_object_ref (cert->priv->asn1); + return NULL; } gboolean diff --git a/smime/lib/e-cert.h b/smime/lib/e-cert.h index 4159c40cb9..0096336741 100644 --- a/smime/lib/e-cert.h +++ b/smime/lib/e-cert.h @@ -95,7 +95,7 @@ const gchar * e_cert_get_serial_number (ECert *cert); const gchar * e_cert_get_sha1_fingerprint (ECert *cert); const gchar * e_cert_get_md5_fingerprint (ECert *cert); -GList * e_cert_get_chain (ECert *cert); +GList * e_cert_get_issuers_chain (ECert *cert); ECert * e_cert_get_ca_cert (ECert *ecert); EASN1Object * e_cert_get_asn1_struct (ECert *cert); |