aboutsummaryrefslogtreecommitdiffstats
path: root/smime/lib/e-cert.c
diff options
context:
space:
mode:
Diffstat (limited to 'smime/lib/e-cert.c')
-rw-r--r--smime/lib/e-cert.c741
1 files changed, 741 insertions, 0 deletions
diff --git a/smime/lib/e-cert.c b/smime/lib/e-cert.c
index 2389cc29c8..173f445c22 100644
--- a/smime/lib/e-cert.c
+++ b/smime/lib/e-cert.c
@@ -90,6 +90,8 @@ struct _ECertPrivate {
char *sha1_fingerprint;
char *md5_fingerprint;
+ EASN1Object *asn1;
+
gboolean delete;
};
@@ -130,6 +132,9 @@ e_cert_dispose (GObject *object)
if (ec->priv->md5_fingerprint)
PORT_Free (ec->priv->md5_fingerprint);
+ if (ec->priv->asn1)
+ g_object_unref (ec->priv->asn1);
+
if (ec->priv->delete) {
printf ("attempting to delete cert marked for deletion\n");
if (e_cert_get_cert_type (ec) == E_CERT_USER) {
@@ -434,6 +439,742 @@ e_cert_get_chain (ECert *ecert)
return l;
}
+static gboolean
+get_int_value (SECItem *versionItem,
+ unsigned long *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 ();
+ unsigned long 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)
+{
+ char *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,
+ char **text)
+{
+ char buf[300];
+ unsigned int len;
+ int written;
+
+ unsigned long val = oid->data[0];
+ unsigned int 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.
+ */
+ unsigned long 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, char **text)
+{
+ SECOidTag oidTag = SECOID_FindOIDTag(oid);
+ char *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_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, char **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;
+ char 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 ();
+ char *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;
+ char *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.
+ */
+ SECItem data;
+ 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;
+ unsigned char 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;
+ unsigned char 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: {
+ char *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 ("");
+ char *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, char **value)
+{
+ CERTRDN** rdns;
+ CERTRDN** rdn;
+ CERTAVA** avas;
+ CERTAVA* ava;
+ SECItem *decodeItem = NULL;
+ GString *final_string = g_string_new ("");
+
+ char *type;
+ GString *avavalue;
+ char *temp;
+ CERTRDN **lastRdn;
+
+ rdns = name->rdns;
+
+ lastRdn = 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 ((char*)decodeItem->data, decodeItem->len);
+
+ SECITEM_FreeItem(decodeItem, PR_TRUE);
+
+ 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 ();
+ char *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);
+
+#if 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(&notBefore);
+ validityData->GetNotAfter(&notAfter);
+ 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;
+ char *text;
+
+ cert->priv->asn1 = e_asn1_object_new ();
+
+ if (cert->priv->cert->nickname)
+ e_asn1_object_set_display_name (cert->priv->asn1, cert->priv->cert->nickname);
+ else if (cert->priv->cn)
+ e_asn1_object_set_display_name (cert->priv->asn1, cert->priv->cn);
+ else
+ e_asn1_object_set_display_name (cert->priv->asn1, cert->priv->cert->subjectName);
+
+ /* 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);
+
+ return g_object_ref (cert->priv->asn1);
+}
+
gboolean
e_cert_mark_for_deletion (ECert *cert)
{