diff options
author | Milan Crha <mcrha@redhat.com> | 2010-06-12 01:28:16 +0800 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2010-06-12 01:28:16 +0800 |
commit | 077116eac4cbfd5f06c44c8f5634469eab3130e6 (patch) | |
tree | 497e15a1663ce562b6b9b6c5e881d4b77afe78f1 | |
parent | 9e99aac0a660952488a91c40196be594367983b3 (diff) | |
download | gsoc2013-evolution-077116eac4cbfd5f06c44c8f5634469eab3130e6.tar.gz gsoc2013-evolution-077116eac4cbfd5f06c44c8f5634469eab3130e6.tar.zst gsoc2013-evolution-077116eac4cbfd5f06c44c8f5634469eab3130e6.zip |
Bug #619218 - Should select imported certificate when succeeded
-rw-r--r-- | smime/gui/certificate-manager.c | 108 | ||||
-rw-r--r-- | smime/lib/e-cert-db.c | 332 | ||||
-rw-r--r-- | smime/lib/e-cert-db.h | 7 |
3 files changed, 400 insertions, 47 deletions
diff --git a/smime/gui/certificate-manager.c b/smime/gui/certificate-manager.c index cc6d702d46..9c28945c42 100644 --- a/smime/gui/certificate-manager.c +++ b/smime/gui/certificate-manager.c @@ -46,6 +46,7 @@ #include <pk11func.h> #include "shell/e-shell.h" +#include "e-util/e-dialog-utils.h" #include "e-util/e-util.h" #include "e-util/e-util-private.h" #include "widgets/misc/e-preferences-window.h" @@ -91,6 +92,18 @@ static void add_contact_cert (CertificateManagerData *cfm, ECert *cert); static void add_ca_cert (CertificateManagerData *cfm, ECert *cert); static void +report_and_free_error (CertificateManagerData *cfm, const gchar *where, GError *error) +{ + g_return_if_fail (cfm != NULL); + + e_notice (gtk_widget_get_toplevel (cfm->yourcerts_treeview), + GTK_MESSAGE_ERROR, "%s: %s", where, error ? error->message : _("Unknown error")); + + if (error) + g_error_free (error); +} + +static void handle_selection_changed (GtkTreeSelection *selection, gint cert_column, GtkWidget *view_button, @@ -153,17 +166,20 @@ import_your (GtkWidget *widget, CertificateManagerData *cfm) if (GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (filesel))) { gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filesel)); + GError *error = NULL; /* destroy dialog to get rid of it in the GUI */ gtk_widget_destroy (filesel); if (e_cert_db_import_pkcs12_file (e_cert_db_peek (), - filename, NULL /* XXX */)) { + filename, &error)) { /* there's no telling how many certificates were added during the import, so we blow away the contact cert display and regenerate it. */ unload_certs (cfm, E_CERT_USER); load_certs (cfm, E_CERT_USER, add_user_cert); gtk_tree_view_expand_all (GTK_TREE_VIEW (cfm->yourcerts_treeview)); + } else { + report_and_free_error (cfm, _("Failed to import user's certificate"), error); } g_free (filename); @@ -189,7 +205,6 @@ delete_your (GtkWidget *widget, CertificateManagerData *cfm) if (cert && e_cert_db_delete_cert (e_cert_db_peek (), cert)) { GtkTreeIter child_iter; - printf ("DELETE\n"); gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (cfm->yourcerts_streemodel), &child_iter, &iter); @@ -243,6 +258,69 @@ backup_all_your (GtkWidget *widget, CertificateManagerData *cfm) /* FIXME: implement */ } +struct find_cert_data { + ECert *cert; + GtkTreePath *path; + gint cert_index; +}; + +static gboolean +find_cert_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) +{ + struct find_cert_data *fcd = data; + ECert *cert = NULL; + + g_return_val_if_fail (model != NULL, TRUE); + g_return_val_if_fail (iter != NULL, TRUE); + g_return_val_if_fail (data != NULL, TRUE); + + gtk_tree_model_get (model, iter, fcd->cert_index, &cert, -1); + + if (cert && g_strcmp0 (e_cert_get_serial_number (cert), e_cert_get_serial_number (fcd->cert)) == 0 + && g_strcmp0 (e_cert_get_subject_name (cert), e_cert_get_subject_name (fcd->cert)) == 0 + && g_strcmp0 (e_cert_get_sha1_fingerprint (cert), e_cert_get_sha1_fingerprint (fcd->cert)) == 0 + && g_strcmp0 (e_cert_get_md5_fingerprint (cert), e_cert_get_md5_fingerprint (fcd->cert)) == 0) { + fcd->path = gtk_tree_path_copy (path); + } + + return fcd->path != NULL; +} + +static void +select_certificate (CertificateManagerData *cfm, GtkTreeView *treeview, ECert *cert) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + struct find_cert_data fcd; + + g_return_if_fail (treeview != NULL); + g_return_if_fail (GTK_IS_TREE_VIEW (treeview)); + g_return_if_fail (cert != NULL); + g_return_if_fail (E_IS_CERT (cert)); + + model = gtk_tree_view_get_model (treeview); + g_return_if_fail (model != NULL); + + fcd.cert = cert; + fcd.path = NULL; + fcd.cert_index = cfm->yourcerts_treeview == GTK_WIDGET (treeview) ? 4 + : cfm->authoritycerts_treeview == GTK_WIDGET (treeview) ? 1 + : 3; + + gtk_tree_model_foreach (model, find_cert_cb, &fcd); + + if (fcd.path) { + gtk_tree_view_expand_to_path (treeview, fcd.path); + + selection = gtk_tree_view_get_selection (treeview); + gtk_tree_selection_select_path (selection, fcd.path); + + gtk_tree_view_scroll_to_cell (treeview, fcd.path, NULL, FALSE, 0.0, 0.0); + + gtk_tree_path_free (fcd.path); + } +} + static void yourcerts_selection_changed (GtkTreeSelection *selection, CertificateManagerData *cfm) { @@ -400,6 +478,8 @@ import_contact (GtkWidget *widget, CertificateManagerData *cfm) if (GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (filesel))) { gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filesel)); + GError *error = NULL; + GSList *imported_certs = NULL; /* destroy dialog to get rid of it in the GUI */ gtk_widget_destroy (filesel); @@ -407,16 +487,24 @@ import_contact (GtkWidget *widget, CertificateManagerData *cfm) if (e_cert_db_import_certs_from_file (e_cert_db_peek (), filename, E_CERT_CONTACT, - NULL)) { + &imported_certs, + &error)) { /* there's no telling how many certificates were added during the import, so we blow away the contact cert display and regenerate it. */ unload_certs (cfm, E_CERT_CONTACT); load_certs (cfm, E_CERT_CONTACT, add_contact_cert); gtk_tree_view_expand_all (GTK_TREE_VIEW (cfm->contactcerts_treeview)); + + if (imported_certs) + select_certificate (cfm, GTK_TREE_VIEW (cfm->contactcerts_treeview), imported_certs->data); + } else { + report_and_free_error (cfm, _("Failed to import contact's certificate"), error); } g_free (filename); + g_slist_foreach (imported_certs, (GFunc) g_object_unref, NULL); + g_slist_free (imported_certs); } else gtk_widget_destroy (filesel); } @@ -439,7 +527,6 @@ delete_contact (GtkWidget *widget, CertificateManagerData *cfm) if (cert && e_cert_db_delete_cert (e_cert_db_peek (), cert)) { GtkTreeIter child_iter; - printf ("DELETE\n"); gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (cfm->contactcerts_streemodel), &child_iter, &iter); @@ -627,6 +714,8 @@ import_ca (GtkWidget *widget, CertificateManagerData *cfm) if (GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (filesel))) { gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filesel)); + GSList *imported_certs = NULL; + GError *error = NULL; /* destroy dialog to get rid of it in the GUI */ gtk_widget_destroy (filesel); @@ -634,14 +723,22 @@ import_ca (GtkWidget *widget, CertificateManagerData *cfm) if (e_cert_db_import_certs_from_file (e_cert_db_peek (), filename, E_CERT_CA, - NULL)) { + &imported_certs, + &error)) { /* there's no telling how many certificates were added during the import, so we blow away the CA cert display and regenerate it. */ unload_certs (cfm, E_CERT_CA); load_certs (cfm, E_CERT_CA, add_ca_cert); + + if (imported_certs) + select_certificate (cfm, GTK_TREE_VIEW (cfm->authoritycerts_treeview), imported_certs->data); + } else { + report_and_free_error (cfm, _("Failed to import certificate authority's certificate"), error); } + g_slist_foreach (imported_certs, (GFunc) g_object_unref, NULL); + g_slist_free (imported_certs); g_free (filename); } else gtk_widget_destroy (filesel); @@ -665,7 +762,6 @@ delete_ca (GtkWidget *widget, CertificateManagerData *cfm) if (cert && e_cert_db_delete_cert (e_cert_db_peek (), cert)) { GtkTreeIter child_iter; - printf ("DELETE\n"); gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (cfm->authoritycerts_streemodel), &child_iter, &iter); diff --git a/smime/lib/e-cert-db.c b/smime/lib/e-cert-db.c index a4fcbe4ac5..833c19b652 100644 --- a/smime/lib/e-cert-db.c +++ b/smime/lib/e-cert-db.c @@ -67,13 +67,13 @@ #include "p12plcy.h" #include "pk11func.h" #include "nssckbi.h" +#include <secerr.h> #include "secmod.h" #include "certdb.h" #include "plstr.h" #include "prprf.h" #include "prmem.h" #include "e-util/e-util.h" -#include "e-util/e-dialog-utils.h" #include "e-util/e-util-private.h" #include <libedataserverui/e-passwords.h> #include <sys/types.h> @@ -96,6 +96,225 @@ struct _ECertDBPrivate { #define PARENT_TYPE G_TYPE_OBJECT static GObjectClass *parent_class; +GQuark +e_certdb_error_quark (void) +{ + static GQuark q = 0; + if (q == 0) + q = g_quark_from_static_string ("e-certdb-error-quark"); + + return q; +} + +static const gchar * +nss_error_to_string (glong errorcode) +{ +#define cs(a,b) case a: return b; + + switch (errorcode) { + cs (SEC_ERROR_IO, "An I/O error occurred during security authorization.") + cs (SEC_ERROR_LIBRARY_FAILURE, "security library failure.") + cs (SEC_ERROR_BAD_DATA, "security library: received bad data.") + cs (SEC_ERROR_OUTPUT_LEN, "security library: output length error.") + cs (SEC_ERROR_INPUT_LEN, "security library has experienced an input length error.") + cs (SEC_ERROR_INVALID_ARGS, "security library: invalid arguments.") + cs (SEC_ERROR_INVALID_ALGORITHM, "security library: invalid algorithm.") + cs (SEC_ERROR_INVALID_AVA, "security library: invalid AVA.") + cs (SEC_ERROR_INVALID_TIME, "Improperly formatted time string.") + cs (SEC_ERROR_BAD_DER, "security library: improperly formatted DER-encoded message.") + cs (SEC_ERROR_BAD_SIGNATURE, "Peer's certificate has an invalid signature.") + cs (SEC_ERROR_EXPIRED_CERTIFICATE, "Peer's Certificate has expired.") + cs (SEC_ERROR_REVOKED_CERTIFICATE, "Peer's Certificate has been revoked.") + cs (SEC_ERROR_UNKNOWN_ISSUER, "Peer's Certificate issuer is not recognized.") + cs (SEC_ERROR_BAD_KEY, "Peer's public key is invalid.") + cs (SEC_ERROR_BAD_PASSWORD, "The security password entered is incorrect.") + cs (SEC_ERROR_RETRY_PASSWORD, "New password entered incorrectly. Please try again.") + cs (SEC_ERROR_NO_NODELOCK, "security library: no nodelock.") + cs (SEC_ERROR_BAD_DATABASE, "security library: bad database.") + cs (SEC_ERROR_NO_MEMORY, "security library: memory allocation failure.") + cs (SEC_ERROR_UNTRUSTED_ISSUER, "Peer's certificate issuer has been marked as not trusted by the user.") + cs (SEC_ERROR_UNTRUSTED_CERT, "Peer's certificate has been marked as not trusted by the user.") + cs (SEC_ERROR_DUPLICATE_CERT, "Certificate already exists in your database.") + cs (SEC_ERROR_DUPLICATE_CERT_NAME, "Downloaded certificate's name duplicates one already in your database.") + cs (SEC_ERROR_ADDING_CERT, "Error adding certificate to database.") + cs (SEC_ERROR_FILING_KEY, "Error refiling the key for this certificate.") + cs (SEC_ERROR_NO_KEY, "The private key for this certificate cannot be found in key database") + cs (SEC_ERROR_CERT_VALID, "This certificate is valid.") + cs (SEC_ERROR_CERT_NOT_VALID, "This certificate is not valid.") + cs (SEC_ERROR_CERT_NO_RESPONSE, "Cert Library: No Response") + cs (SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, "The certificate issuer's certificate has expired. Check your system date and time.") + cs (SEC_ERROR_CRL_EXPIRED, "The CRL for the certificate's issuer has expired. Update it or check your system date and time.") + cs (SEC_ERROR_CRL_BAD_SIGNATURE, "The CRL for the certificate's issuer has an invalid signature.") + cs (SEC_ERROR_CRL_INVALID, "New CRL has an invalid format.") + cs (SEC_ERROR_EXTENSION_VALUE_INVALID, "Certificate extension value is invalid.") + cs (SEC_ERROR_EXTENSION_NOT_FOUND, "Certificate extension not found.") + cs (SEC_ERROR_CA_CERT_INVALID, "Issuer certificate is invalid.") + cs (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, "Certificate path length constraint is invalid.") + cs (SEC_ERROR_CERT_USAGES_INVALID, "Certificate usages field is invalid.") + cs (SEC_INTERNAL_ONLY, "**Internal ONLY module**") + cs (SEC_ERROR_INVALID_KEY, "The key does not support the requested operation.") + cs (SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, "Certificate contains unknown critical extension.") + cs (SEC_ERROR_OLD_CRL, "New CRL is not later than the current one.") + cs (SEC_ERROR_NO_EMAIL_CERT, "Not encrypted or signed: you do not yet have an email certificate.") + cs (SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, "Not encrypted: you do not have certificates for each of the recipients.") + cs (SEC_ERROR_NOT_A_RECIPIENT, "Cannot decrypt: you are not a recipient, or matching certificate and private key not found.") + cs (SEC_ERROR_PKCS7_KEYALG_MISMATCH, "Cannot decrypt: key encryption algorithm does not match your certificate.") + cs (SEC_ERROR_PKCS7_BAD_SIGNATURE, "Signature verification failed: no signer found, too many signers found, or improper or corrupted data.") + cs (SEC_ERROR_UNSUPPORTED_KEYALG, "Unsupported or unknown key algorithm.") + cs (SEC_ERROR_DECRYPTION_DISALLOWED, "Cannot decrypt: encrypted using a disallowed algorithm or key size.") + cs (XP_SEC_FORTEZZA_BAD_CARD, "Fortezza card has not been properly initialized. Please remove it and return it to your issuer.") + cs (XP_SEC_FORTEZZA_NO_CARD, "No Fortezza cards Found") + cs (XP_SEC_FORTEZZA_NONE_SELECTED, "No Fortezza card selected") + cs (XP_SEC_FORTEZZA_MORE_INFO, "Please select a personality to get more info on") + cs (XP_SEC_FORTEZZA_PERSON_NOT_FOUND, "Personality not found") + cs (XP_SEC_FORTEZZA_NO_MORE_INFO, "No more information on that Personality") + cs (XP_SEC_FORTEZZA_BAD_PIN, "Invalid Pin") + cs (XP_SEC_FORTEZZA_PERSON_ERROR, "Couldn't initialize Fortezza personalities.") + cs (SEC_ERROR_NO_KRL, "No KRL for this site's certificate has been found.") + cs (SEC_ERROR_KRL_EXPIRED, "The KRL for this site's certificate has expired.") + cs (SEC_ERROR_KRL_BAD_SIGNATURE, "The KRL for this site's certificate has an invalid signature.") + cs (SEC_ERROR_REVOKED_KEY, "The key for this site's certificate has been revoked.") + cs (SEC_ERROR_KRL_INVALID, "New KRL has an invalid format.") + cs (SEC_ERROR_NEED_RANDOM, "security library: need random data.") + cs (SEC_ERROR_NO_MODULE, "security library: no security module can perform the requested operation.") + cs (SEC_ERROR_NO_TOKEN, "The security card or token does not exist, needs to be initialized, or has been removed.") + cs (SEC_ERROR_READ_ONLY, "security library: read-only database.") + cs (SEC_ERROR_NO_SLOT_SELECTED, "No slot or token was selected.") + cs (SEC_ERROR_CERT_NICKNAME_COLLISION, "A certificate with the same nickname already exists.") + cs (SEC_ERROR_KEY_NICKNAME_COLLISION, "A key with the same nickname already exists.") + cs (SEC_ERROR_SAFE_NOT_CREATED, "error while creating safe object") + cs (SEC_ERROR_BAGGAGE_NOT_CREATED, "error while creating baggage object") + cs (XP_JAVA_REMOVE_PRINCIPAL_ERROR, "Couldn't remove the principal") + cs (XP_JAVA_DELETE_PRIVILEGE_ERROR, "Couldn't delete the privilege") + cs (XP_JAVA_CERT_NOT_EXISTS_ERROR, "This principal doesn't have a certificate") + cs (SEC_ERROR_BAD_EXPORT_ALGORITHM, "Required algorithm is not allowed.") + cs (SEC_ERROR_EXPORTING_CERTIFICATES, "Error attempting to export certificates.") + cs (SEC_ERROR_IMPORTING_CERTIFICATES, "Error attempting to import certificates.") + cs (SEC_ERROR_PKCS12_DECODING_PFX, "Unable to import. Decoding error. File not valid.") + cs (SEC_ERROR_PKCS12_INVALID_MAC, "Unable to import. Invalid MAC. Incorrect password or corrupt file.") + cs (SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, "Unable to import. MAC algorithm not supported.") + cs (SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE, "Unable to import. Only password integrity and privacy modes supported.") + cs (SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, "Unable to import. File structure is corrupt.") + cs (SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, "Unable to import. Encryption algorithm not supported.") + cs (SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, "Unable to import. File version not supported.") + cs (SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT, "Unable to import. Incorrect privacy password.") + cs (SEC_ERROR_PKCS12_CERT_COLLISION, "Unable to import. Same nickname already exists in database.") + cs (SEC_ERROR_USER_CANCELLED, "The user pressed cancel.") + cs (SEC_ERROR_PKCS12_DUPLICATE_DATA, "Not imported, already in database.") + cs (SEC_ERROR_MESSAGE_SEND_ABORTED, "Message not sent.") + cs (SEC_ERROR_INADEQUATE_KEY_USAGE, "Certificate key usage inadequate for attempted operation.") + cs (SEC_ERROR_INADEQUATE_CERT_TYPE, "Certificate type not approved for application.") + cs (SEC_ERROR_CERT_ADDR_MISMATCH, "Address in signing certificate does not match address in message headers.") + cs (SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, "Unable to import. Error attempting to import private key.") + cs (SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, "Unable to import. Error attempting to import certificate chain.") + cs (SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, "Unable to export. Unable to locate certificate or key by nickname.") + cs (SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, "Unable to export. Private Key could not be located and exported.") + cs (SEC_ERROR_PKCS12_UNABLE_TO_WRITE, "Unable to export. Unable to write the export file.") + cs (SEC_ERROR_PKCS12_UNABLE_TO_READ, "Unable to import. Unable to read the import file.") + cs (SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, "Unable to export. Key database corrupt or deleted.") + cs (SEC_ERROR_KEYGEN_FAIL, "Unable to generate public/private key pair.") + cs (SEC_ERROR_INVALID_PASSWORD, "Password entered is invalid. Please pick a different one.") + cs (SEC_ERROR_RETRY_OLD_PASSWORD, "Old password entered incorrectly. Please try again.") + cs (SEC_ERROR_BAD_NICKNAME, "Certificate nickname already in use.") + cs (SEC_ERROR_NOT_FORTEZZA_ISSUER, "Peer FORTEZZA chain has a non-FORTEZZA Certificate.") + cs (SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, "A sensitive key cannot be moved to the slot where it is needed.") + cs (SEC_ERROR_JS_INVALID_MODULE_NAME, "Invalid module name.") + cs (SEC_ERROR_JS_INVALID_DLL, "Invalid module path/filename") + cs (SEC_ERROR_JS_ADD_MOD_FAILURE, "Unable to add module") + cs (SEC_ERROR_JS_DEL_MOD_FAILURE, "Unable to delete module") + cs (SEC_ERROR_OLD_KRL, "New KRL is not later than the current one.") + cs (SEC_ERROR_CKL_CONFLICT, "New CKL has different issuer than current CKL. Delete current CKL.") + cs (SEC_ERROR_CERT_NOT_IN_NAME_SPACE, "The Certifying Authority for this certificate is not permitted to issue a certificate with this name.") + cs (SEC_ERROR_KRL_NOT_YET_VALID, "The key revocation list for this certificate is not yet valid.") + cs (SEC_ERROR_CRL_NOT_YET_VALID, "The certificate revocation list for this certificate is not yet valid.") + cs (SEC_ERROR_UNKNOWN_CERT, "The requested certificate could not be found.") + cs (SEC_ERROR_UNKNOWN_SIGNER, "The signer's certificate could not be found.") + cs (SEC_ERROR_CERT_BAD_ACCESS_LOCATION, "The location for the certificate status server has invalid format.") + cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, "The OCSP response cannot be fully decoded; it is of an unknown type.") + cs (SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, "The OCSP server returned unexpected/invalid HTTP data.") + cs (SEC_ERROR_OCSP_MALFORMED_REQUEST, "The OCSP server found the request to be corrupted or improperly formed.") + cs (SEC_ERROR_OCSP_SERVER_ERROR, "The OCSP server experienced an internal error.") + cs (SEC_ERROR_OCSP_TRY_SERVER_LATER, "The OCSP server suggests trying again later.") + cs (SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, "The OCSP server requires a signature on this request.") + cs (SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, "The OCSP server has refused this request as unauthorized.") + cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, "The OCSP server returned an unrecognizable status.") + cs (SEC_ERROR_OCSP_UNKNOWN_CERT, "The OCSP server has no status for the certificate.") + cs (SEC_ERROR_OCSP_NOT_ENABLED, "You must enable OCSP before performing this operation.") + cs (SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, "You must set the OCSP default responder before performing this operation.") + cs (SEC_ERROR_OCSP_MALFORMED_RESPONSE, "The response from the OCSP server was corrupted or improperly formed.") + cs (SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, "The signer of the OCSP response is not authorized to give status for this certificate.") + cs (SEC_ERROR_OCSP_FUTURE_RESPONSE, "The OCSP response is not yet valid (contains a date in the future).") + cs (SEC_ERROR_OCSP_OLD_RESPONSE, "The OCSP response contains out-of-date information.") + cs (SEC_ERROR_DIGEST_NOT_FOUND, "The CMS or PKCS #7 Digest was not found in signed message.") + cs (SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, "The CMS or PKCS #7 Message type is unsupported.") + cs (SEC_ERROR_MODULE_STUCK, "PKCS #11 module could not be removed because it is still in use.") + cs (SEC_ERROR_BAD_TEMPLATE, "Could not decode ASN.1 data. Specified template was invalid.") + cs (SEC_ERROR_CRL_NOT_FOUND, "No matching CRL was found.") + cs (SEC_ERROR_REUSED_ISSUER_AND_SERIAL, "You are attempting to import a cert with the same issuer/serial as an existing cert, but that is not the same cert.") + cs (SEC_ERROR_BUSY, "NSS could not shutdown. Objects are still in use.") + cs (SEC_ERROR_EXTRA_INPUT, "DER-encoded message contained extra unused data.") + cs (SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, "Unsupported elliptic curve.") + cs (SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, "Unsupported elliptic curve point form.") + cs (SEC_ERROR_UNRECOGNIZED_OID, "Unrecognized Object Identifier.") + cs (SEC_ERROR_OCSP_INVALID_SIGNING_CERT, "Invalid OCSP signing certificate in OCSP response.") + cs (SEC_ERROR_REVOKED_CERTIFICATE_CRL, "Certificate is revoked in issuer's certificate revocation list.") + cs (SEC_ERROR_REVOKED_CERTIFICATE_OCSP, "Issuer's OCSP responder reports certificate is revoked.") + cs (SEC_ERROR_CRL_INVALID_VERSION, "Issuer's Certificate Revocation List has an unknown version number.") + cs (SEC_ERROR_CRL_V1_CRITICAL_EXTENSION, "Issuer's V1 Certificate Revocation List has a critical extension.") + cs (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION, "Issuer's V2 Certificate Revocation List has an unknown critical extension.") + cs (SEC_ERROR_UNKNOWN_OBJECT_TYPE, "Unknown object type specified.") + cs (SEC_ERROR_INCOMPATIBLE_PKCS11, "PKCS #11 driver violates the spec in an incompatible way.") + cs (SEC_ERROR_NO_EVENT, "No new slot event is available at this time.") + cs (SEC_ERROR_CRL_ALREADY_EXISTS, "CRL already exists.") + cs (SEC_ERROR_NOT_INITIALIZED, "NSS is not initialized.") + cs (SEC_ERROR_TOKEN_NOT_LOGGED_IN, "The operation failed because the PKCS#11 token is not logged in.") + cs (SEC_ERROR_OCSP_RESPONDER_CERT_INVALID, "Configured OCSP responder's certificate is invalid.") + cs (SEC_ERROR_OCSP_BAD_SIGNATURE, "OCSP response has an invalid signature.") + + #if defined (NSS_VMAJOR) && defined (NSS_VMINOR) && defined (NSS_VPATCH) && (NSS_VMAJOR > 3 || (NSS_VMAJOR == 3 && NSS_VMINOR > 12) || (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 2)) + cs (SEC_ERROR_OUT_OF_SEARCH_LIMITS, "Cert validation search is out of search limits") + cs (SEC_ERROR_INVALID_POLICY_MAPPING, "Policy mapping contains anypolicy") + cs (SEC_ERROR_POLICY_VALIDATION_FAILED, "Cert chain fails policy validation") + cs (SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE, "Unknown location type in cert AIA extension") + cs (SEC_ERROR_BAD_HTTP_RESPONSE, "Server returned bad HTTP response") + cs (SEC_ERROR_BAD_LDAP_RESPONSE, "Server returned bad LDAP response") + cs (SEC_ERROR_FAILED_TO_ENCODE_DATA, "Failed to encode data with ASN1 encoder") + cs (SEC_ERROR_BAD_INFO_ACCESS_LOCATION, "Bad information access location in cert extension") + cs (SEC_ERROR_LIBPKIX_INTERNAL, "Libpkix internal error occured during cert validation.") + cs (SEC_ERROR_PKCS11_GENERAL_ERROR, "A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred.") + cs (SEC_ERROR_PKCS11_FUNCTION_FAILED, "A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed. Trying the same operation again might succeed.") + cs (SEC_ERROR_PKCS11_DEVICE_ERROR, "A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.") + #endif + } + + #undef cs + + return NULL; +} + +static void +set_nss_error (GError **error) +{ + glong err_code; + const gchar *err_str; + + if (!error) + return; + + g_return_if_fail (*error == NULL); + + err_code = PORT_GetError (); + + if (!err_code) + return; + + err_str = nss_error_to_string (err_code); + if (!err_str) + return; + + *error = g_error_new_literal (E_CERTDB_ERROR, err_code, err_str); +} + static SECStatus PR_CALLBACK collect_certs(gpointer arg, SECItem **certs, gint numcerts) { @@ -437,7 +656,7 @@ e_cert_db_find_cert_by_nickname (ECertDB *certdb, return ecert; } else { - /* XXX gerror */ + set_nss_error (error); return NULL; } } @@ -456,7 +675,7 @@ e_cert_db_find_cert_by_key (ECertDB *certdb, CERTCertificate *cert; if (!db_key) { - /* XXX gerror */ + set_nss_error (error); return NULL; } @@ -481,7 +700,7 @@ e_cert_db_find_cert_by_key (ECertDB *certdb, return e_cert; } - /* XXX gerror */ + set_nss_error (error); return NULL; } @@ -521,7 +740,7 @@ e_cert_db_find_cert_by_email_address (ECertDB *certdb, CERT_GetDefaultCertDB(), (gchar *) email); if (!any_cert) { - /* XXX gerror */ + set_nss_error (error); return NULL; } @@ -532,21 +751,21 @@ e_cert_db_find_cert_by_email_address (ECertDB *certdb, &any_cert->derSubject, PR_Now(), PR_TRUE); if (!certlist) { - /* XXX gerror */ + set_nss_error (error); CERT_DestroyCertificate(any_cert); return NULL; } if (SECSuccess != CERT_FilterCertListByUsage ( certlist, certUsageEmailRecipient, PR_FALSE)) { - /* XXX gerror */ + set_nss_error (error); CERT_DestroyCertificate(any_cert); CERT_DestroyCertList (certlist); return NULL; } if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist)) { - /* XXX gerror */ + set_nss_error (error); CERT_DestroyCertificate(any_cert); CERT_DestroyCertList (certlist); return NULL; @@ -653,12 +872,12 @@ handle_ca_cert_download(ECertDB *cert_db, GList *certs, GError **error) } if (!certToShow) { - /* XXX gerror */ + set_nss_error (error); return FALSE; } if (!e_cert_get_raw_der (certToShow, &raw_der, &der.len)) { - /* XXX gerror */ + set_nss_error (error); return FALSE; } @@ -674,6 +893,7 @@ handle_ca_cert_download(ECertDB *cert_db, GList *certs, GError **error) } if (!tmpCert) { g_warning ("Couldn't create cert from DER blob"); + set_nss_error (error); return FALSE; } } @@ -683,9 +903,8 @@ handle_ca_cert_download(ECertDB *cert_db, GList *certs, GError **error) #endif if (tmpCert->isperm) { - /* XXX we shouldn't be popping up dialogs in this code. */ - e_notice (NULL, GTK_MESSAGE_WARNING, _("Certificate already exists")); - /* XXX gerror */ + if (error && !*error) + *error = g_error_new_literal (E_CERTDB_ERROR, 0, _("Certificate already exists")); return FALSE; } else { @@ -697,7 +916,7 @@ handle_ca_cert_download(ECertDB *cert_db, GList *certs, GError **error) if (!confirm_download_ca_cert ( cert_db, certToShow, &trust_ssl, &trust_email, &trust_objsign)) { - /* XXX gerror */ + set_nss_error (error); return FALSE; } @@ -718,8 +937,8 @@ handle_ca_cert_download(ECertDB *cert_db, GList *certs, GError **error) nickname, &trust); - if (srv != SECSuccess) { - /* XXX gerror */ + if (srv != SECSuccess && PORT_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) { + set_nss_error (error); return FALSE; } @@ -763,7 +982,7 @@ e_cert_db_delete_cert (ECertDB *certdb, nsNSSCertificate *nssCert = NS_STATIC_CAST(nsNSSCertificate*, aCert); */ CERTCertificate *cert; - SECStatus srv = SECSuccess; + if (!e_cert_mark_for_deletion (ecert)) { return FALSE; } @@ -780,12 +999,11 @@ e_cert_db_delete_cert (ECertDB *certdb, CERTCertTrust trust; e_cert_trust_init_with_values (&trust, 0, 0, 0); - srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), + CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust); } - /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert deleted: %d", srv));*/ - return (srv) ? FALSE : TRUE; + return TRUE; } /* importing certificates */ @@ -793,6 +1011,7 @@ gboolean e_cert_db_import_certs (ECertDB *certdb, gchar *data, guint32 length, ECertType cert_type, + GSList **imported_certs, GError **error) { /*nsNSSShutDownPreventionLock locker;*/ @@ -803,7 +1022,7 @@ e_cert_db_import_certs (ECertDB *certdb, gboolean rv; if (!certCollection) { - /* XXX gerror */ + set_nss_error (error); PORT_FreeArena(arena, PR_FALSE); return FALSE; } @@ -815,7 +1034,7 @@ e_cert_db_import_certs (ECertDB *certdb, cert = e_cert_new_from_der ((gchar *)currItem->data, currItem->len); if (!cert) { - /* XXX gerror */ + set_nss_error (error); g_list_foreach (certs, (GFunc)g_object_unref, NULL); g_list_free (certs); PORT_FreeArena(arena, PR_FALSE); @@ -826,10 +1045,24 @@ e_cert_db_import_certs (ECertDB *certdb, switch (cert_type) { case E_CERT_CA: rv = handle_ca_cert_download(certdb, certs, error); + if (rv && imported_certs) { + GList *l; + + /* copy certificates to the caller */ + *imported_certs = NULL; + for (l = certs; l; l = l->next) { + ECert *cert = l->data; + + if (cert) + *imported_certs = g_slist_prepend (*imported_certs, g_object_ref (cert)); + } + + *imported_certs = g_slist_reverse (*imported_certs); + } break; default: /* We only deal with import CA certs in this method currently.*/ - /* XXX gerror */ + set_nss_error (error); PORT_FreeArena(arena, PR_FALSE); rv = FALSE; } @@ -843,6 +1076,7 @@ e_cert_db_import_certs (ECertDB *certdb, gboolean e_cert_db_import_email_cert (ECertDB *certdb, gchar *data, guint32 length, + GSList **imported_certs, GError **error) { /*nsNSSShutDownPreventionLock locker;*/ @@ -856,8 +1090,7 @@ e_cert_db_import_email_cert (ECertDB *certdb, CERTDERCerts *certCollection = e_cert_db_get_certs_from_package (arena, data, length); if (!certCollection) { - /* XXX g_error */ - + set_nss_error (error); PORT_FreeArena(arena, PR_FALSE); return FALSE; } @@ -865,14 +1098,14 @@ e_cert_db_import_email_cert (ECertDB *certdb, cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certCollection->rawCerts, (gchar *)NULL, PR_FALSE, PR_TRUE); if (!cert) { - /* XXX g_error */ + set_nss_error (error); rv = FALSE; goto loser; } numcerts = certCollection->numcerts; rawCerts = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts); if (!rawCerts) { - /* XXX g_error */ + set_nss_error (error); rv = FALSE; goto loser; } @@ -885,11 +1118,26 @@ e_cert_db_import_email_cert (ECertDB *certdb, numcerts, rawCerts, NULL, PR_TRUE, PR_FALSE, NULL); if (srv != SECSuccess) { - /* XXX g_error */ + set_nss_error (error); rv = FALSE; goto loser; } CERT_SaveSMimeProfile(cert, NULL, NULL); + + if (imported_certs) { + *imported_certs = NULL; + for (i = 0; i < certCollection->numcerts; i++) { + SECItem *currItem = &certCollection->rawCerts[i]; + ECert *cert; + + cert = e_cert_new_from_der ((gchar *)currItem->data, currItem->len); + if (cert) + *imported_certs = g_slist_prepend (*imported_certs, cert); + } + + *imported_certs = g_slist_reverse (*imported_certs); + } + PORT_Free(rawCerts); loser: if (cert) @@ -1041,26 +1289,26 @@ e_cert_db_import_user_cert (ECertDB *certdb, arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { - /* XXX g_error */ + set_nss_error (error); goto loser; } collectArgs = e_cert_db_get_certs_from_package (arena, data, length); if (!collectArgs) { - /* XXX g_error */ + set_nss_error (error); goto loser; } cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts, (gchar *)NULL, PR_FALSE, PR_TRUE); if (!cert) { - /* XXX g_error */ + set_nss_error (error); goto loser; } slot = PK11_KeyForCertExists(cert, NULL, NULL); if (slot == NULL) { - /* XXX g_error */ + set_nss_error (error); goto loser; } PK11_FreeSlot(slot); @@ -1079,7 +1327,7 @@ e_cert_db_import_user_cert (ECertDB *certdb, /* user wants to import the cert */ slot = PK11_ImportCertForKey(cert, nickname, NULL); if (!slot) { - /* XXX g_error */ + set_nss_error (error); goto loser; } PK11_FreeSlot(slot); @@ -1105,6 +1353,7 @@ e_cert_db_import_user_cert (ECertDB *certdb, gboolean e_cert_db_import_server_cert (ECertDB *certdb, gchar *data, guint32 length, + GSList **imported_certs, GError **error) { /* not c&p'ing this over at the moment, as we don't have a UI @@ -1116,6 +1365,7 @@ gboolean e_cert_db_import_certs_from_file (ECertDB *cert_db, const gchar *file_path, ECertType cert_type, + GSList **imported_certs, GError **error) { gboolean rv; @@ -1133,25 +1383,25 @@ e_cert_db_import_certs_from_file (ECertDB *cert_db, default: /* not supported (yet) */ - /* XXX gerror */ + set_nss_error (error); return FALSE; } fd = g_open (file_path, O_RDONLY|O_BINARY, 0); if (fd == -1) { - /* XXX gerror */ + set_nss_error (error); return FALSE; } if (-1 == fstat (fd, &sb)) { - /* XXX gerror */ + set_nss_error (error); close (fd); return FALSE; } buf = g_malloc (sb.st_size); if (!buf) { - /* XXX gerror */ + set_nss_error (error); close (fd); return FALSE; } @@ -1161,7 +1411,7 @@ e_cert_db_import_certs_from_file (ECertDB *cert_db, close (fd); if (bytes_read != sb.st_size) { - /* XXX gerror */ + set_nss_error (error); rv = FALSE; } else { @@ -1169,15 +1419,15 @@ e_cert_db_import_certs_from_file (ECertDB *cert_db, switch (cert_type) { case E_CERT_CA: - rv = e_cert_db_import_certs (cert_db, buf, bytes_read, cert_type, error); + rv = e_cert_db_import_certs (cert_db, buf, bytes_read, cert_type, imported_certs, error); break; case E_CERT_SITE: - rv = e_cert_db_import_server_cert (cert_db, buf, bytes_read, error); + rv = e_cert_db_import_server_cert (cert_db, buf, bytes_read, imported_certs, error); break; case E_CERT_CONTACT: - rv = e_cert_db_import_email_cert (cert_db, buf, bytes_read, error); + rv = e_cert_db_import_email_cert (cert_db, buf, bytes_read, imported_certs, error); break; default: diff --git a/smime/lib/e-cert-db.h b/smime/lib/e-cert-db.h index 0e19e002c5..7d5f1855c2 100644 --- a/smime/lib/e-cert-db.h +++ b/smime/lib/e-cert-db.h @@ -34,6 +34,9 @@ #define E_IS_CERT_DB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CERT_DB)) #define E_CERT_DB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CERT_DB, ECertDBClass)) +#define E_CERTDB_ERROR e_certdb_error_quark() +GQuark e_certdb_error_quark (void) G_GNUC_CONST; + typedef struct _ECertDB ECertDB; typedef struct _ECertDBClass ECertDBClass; typedef struct _ECertDBPrivate ECertDBPrivate; @@ -102,10 +105,12 @@ gboolean e_cert_db_delete_cert (ECertDB *certdb, gboolean e_cert_db_import_certs (ECertDB *certdb, gchar *data, guint32 length, ECertType cert_type, + GSList **imported_certs, GError **error); gboolean e_cert_db_import_email_cert (ECertDB *certdb, gchar *data, guint32 length, + GSList **imported_certs, GError **error); gboolean e_cert_db_import_user_cert (ECertDB *certdb, @@ -114,11 +119,13 @@ gboolean e_cert_db_import_user_cert (ECertDB *certdb, gboolean e_cert_db_import_server_cert (ECertDB *certdb, gchar *data, guint32 length, + GSList **imported_certs, GError **error); gboolean e_cert_db_import_certs_from_file (ECertDB *cert_db, const gchar *file_path, ECertType cert_type, + GSList **imported_certs, GError **error); gboolean e_cert_db_import_pkcs12_file (ECertDB *cert_db, |