diff options
Diffstat (limited to 'smime/lib/e-cert.c')
-rw-r--r-- | smime/lib/e-cert.c | 769 |
1 files changed, 13 insertions, 756 deletions
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 |