aboutsummaryrefslogtreecommitdiffstats
path: root/smime/lib/e-cert-db.c
diff options
context:
space:
mode:
Diffstat (limited to 'smime/lib/e-cert-db.c')
-rw-r--r--smime/lib/e-cert-db.c1521
1 files changed, 1521 insertions, 0 deletions
diff --git a/smime/lib/e-cert-db.c b/smime/lib/e-cert-db.c
new file mode 100644
index 0000000000..bb4a68e61d
--- /dev/null
+++ b/smime/lib/e-cert-db.c
@@ -0,0 +1,1521 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* The following is the mozilla license blurb, as the bodies some of
+ * these functions were derived from the mozilla source. */
+/* e-cert-db.c
+ *
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+/*
+ * Author: Chris Toshok (toshok@ximian.com)
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include <camel/camel.h>
+
+/* private NSS defines used by PSM */
+/* (must be declated before cert.h) */
+#define CERT_NewTempCertificate __CERT_NewTempCertificate
+#define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm
+
+#include "e-cert-db.h"
+#include "e-cert-trust.h"
+#include "e-pkcs12.h"
+
+#include "gmodule.h"
+
+#include "nss.h"
+#include "ssl.h"
+#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-util-private.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+enum {
+ PK11_PASSWD,
+ PK11_CHANGE_PASSWD,
+ CONFIRM_CA_CERT_IMPORT,
+ LAST_SIGNAL
+};
+
+static guint e_cert_db_signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (ECertDB, e_cert_db, G_TYPE_OBJECT)
+
+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)
+{
+ CERTDERCerts *collectArgs;
+ SECItem *cert;
+ SECStatus rv;
+
+ collectArgs = (CERTDERCerts *) arg;
+
+ collectArgs->numcerts = numcerts;
+ collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc (
+ collectArgs->arena, sizeof (SECItem) * numcerts);
+ if (collectArgs->rawCerts == NULL)
+ return (SECFailure);
+
+ cert = collectArgs->rawCerts;
+
+ while (numcerts--) {
+ rv = SECITEM_CopyItem (collectArgs->arena, cert, *certs);
+ if (rv == SECFailure)
+ return (SECFailure);
+ cert++;
+ certs++;
+ }
+
+ return (SECSuccess);
+}
+
+static CERTDERCerts *
+e_cert_db_get_certs_from_package (PRArenaPool *arena,
+ gchar *data,
+ guint32 length)
+{
+ /*nsNSSShutDownPreventionLock locker;*/
+ CERTDERCerts *collectArgs =
+ (CERTDERCerts *) PORT_ArenaZAlloc (arena, sizeof (CERTDERCerts));
+ SECStatus sec_rv;
+
+ if (!collectArgs)
+ return NULL;
+
+ collectArgs->arena = arena;
+ sec_rv = CERT_DecodeCertPackage (
+ data,
+ length, collect_certs,
+ (gpointer) collectArgs);
+
+ if (sec_rv != SECSuccess)
+ return NULL;
+
+ return collectArgs;
+}
+
+#ifdef notyet
+PRBool
+ucs2_ascii_conversion_fn (PRBool toUnicode,
+ guchar *inBuf,
+ guint inBufLen,
+ guchar *outBuf,
+ guint maxOutBufLen,
+ guint *outBufLen,
+ PRBool swapBytes)
+{
+ printf ("in ucs2_ascii_conversion_fn\n");
+}
+#endif
+
+static gchar * PR_CALLBACK
+pk11_password (PK11SlotInfo *slot,
+ PRBool retry,
+ gpointer arg)
+{
+ gchar *pwd;
+ gchar *nsspwd;
+
+ gboolean rv = FALSE;
+
+ g_signal_emit (
+ e_cert_db_peek (),
+ e_cert_db_signals[PK11_PASSWD], 0,
+ slot,
+ retry,
+ &pwd,
+ &rv);
+
+ if (pwd == NULL)
+ return NULL;
+
+ nsspwd = PORT_Strdup (pwd);
+ memset (pwd, 0, strlen (pwd));
+ g_free (pwd);
+ return nsspwd;
+}
+
+static void
+initialize_nss (void)
+{
+ /* Use camel_init() to initialise NSS consistently... */
+ camel_init (e_get_user_data_dir (), TRUE);
+
+ /* ... except for the bits we only seem to do here. FIXME */
+ PK11_SetPasswordFunc (pk11_password);
+
+ /* Enable ciphers for PKCS#12 */
+ SEC_PKCS12EnableCipher (PKCS12_RC4_40, 1);
+ SEC_PKCS12EnableCipher (PKCS12_RC4_128, 1);
+ SEC_PKCS12EnableCipher (PKCS12_RC2_CBC_40, 1);
+ SEC_PKCS12EnableCipher (PKCS12_RC2_CBC_128, 1);
+ SEC_PKCS12EnableCipher (PKCS12_DES_56, 1);
+ SEC_PKCS12EnableCipher (PKCS12_DES_EDE3_168, 1);
+ SEC_PKCS12SetPreferredCipher (PKCS12_DES_EDE3_168, 1);
+#ifdef notyet
+ PORT_SetUCS2_ASCIIConversionFunction (ucs2_ascii_conversion_fn);
+#endif
+}
+
+static void
+install_loadable_roots (void)
+{
+ SECMODModuleList *list = SECMOD_GetDefaultModuleList ();
+ SECMODListLock *lock = SECMOD_GetDefaultModuleListLock ();
+ SECMODModule *RootsModule = NULL;
+ gint i;
+
+ SECMOD_GetReadLock (lock);
+ while (!RootsModule && list) {
+ SECMODModule *module = list->module;
+
+ for (i = 0; i < module->slotCount; i++) {
+ PK11SlotInfo *slot = module->slots[i];
+ if (PK11_IsPresent (slot)) {
+ if (PK11_HasRootCerts (slot)) {
+ RootsModule = module;
+ break;
+ }
+ }
+ }
+
+ list = list->next;
+ }
+ SECMOD_ReleaseReadLock (lock);
+
+ if (RootsModule) {
+ /* Check version, and unload module if it is too old */
+ CK_INFO info;
+
+ if (PK11_GetModInfo (RootsModule, &info) != SECSuccess) {
+ /* Do not use this module */
+ RootsModule = NULL;
+ } else {
+ /* NSS_BUILTINS_LIBRARY_VERSION_MAJOR and NSS_BUILTINS_LIBRARY_VERSION_MINOR
+ * define the version we expect to have.
+ * Later version are fine.
+ * Older versions are not ok, and we will replace with our own version.
+ */
+ if ((info.libraryVersion.major < NSS_BUILTINS_LIBRARY_VERSION_MAJOR)
+ || (info.libraryVersion.major == NSS_BUILTINS_LIBRARY_VERSION_MAJOR
+ && info.libraryVersion.minor < NSS_BUILTINS_LIBRARY_VERSION_MINOR)) {
+ PRInt32 modType;
+
+ SECMOD_DeleteModule (RootsModule->commonName, &modType);
+
+ RootsModule = NULL;
+ }
+ }
+ }
+
+ if (!RootsModule) {
+#ifndef G_OS_WIN32
+ /* grovel in various places for mozilla's built-in
+ * cert module.
+ *
+ * XXX yes this is gross. *sigh *
+ */
+ const gchar *paths_to_check[] = {
+#ifdef MOZILLA_NSS_LIB_DIR
+ MOZILLA_NSS_LIB_DIR,
+#endif
+ "/usr/lib",
+ "/usr/lib/mozilla",
+ "/opt/mozilla/lib",
+ "/opt/mozilla/lib/mozilla"
+ };
+
+ for (i = 0; i < G_N_ELEMENTS (paths_to_check); i++) {
+ gchar *dll_path = g_module_build_path (paths_to_check[i], "nssckbi");
+
+ if (g_file_test (dll_path, G_FILE_TEST_EXISTS)) {
+ PRInt32 modType;
+
+ /* Delete the existing module */
+ SECMOD_DeleteModule ("Mozilla Root Certs", &modType);
+
+ SECMOD_AddNewModule ("Mozilla Root Certs",dll_path, 0, 0);
+ g_free (dll_path);
+ break;
+ }
+
+ g_free (dll_path);
+ }
+#else
+ /* FIXME: Might be useful to look up if there is a
+ * Mozilla installation on the machine and use the
+ * nssckbi.dll from there.
+ */
+#endif
+ }
+}
+
+static void
+e_cert_db_class_init (ECertDBClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+
+ initialize_nss ();
+ /* check to see if you have a rootcert module installed */
+ install_loadable_roots ();
+
+ e_cert_db_signals[PK11_PASSWD] = g_signal_new (
+ "pk11_passwd",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECertDBClass, pk11_passwd),
+ NULL, NULL,
+ e_marshal_BOOLEAN__POINTER_BOOLEAN_POINTER,
+ G_TYPE_BOOLEAN, 3,
+ G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_POINTER);
+
+ e_cert_db_signals[PK11_CHANGE_PASSWD] = g_signal_new (
+ "pk11_change_passwd",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECertDBClass, pk11_change_passwd),
+ NULL, NULL,
+ e_marshal_BOOLEAN__POINTER_POINTER,
+ G_TYPE_BOOLEAN, 2,
+ G_TYPE_POINTER, G_TYPE_POINTER);
+
+ e_cert_db_signals[CONFIRM_CA_CERT_IMPORT] = g_signal_new (
+ "confirm_ca_cert_import",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECertDBClass, confirm_ca_cert_import),
+ NULL, NULL,
+ e_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER,
+ G_TYPE_BOOLEAN, 4,
+ G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
+}
+
+static void
+e_cert_db_init (ECertDB *ec)
+{
+}
+
+GMutex init_mutex;
+static ECertDB *cert_db = NULL;
+
+ECertDB *
+e_cert_db_peek (void)
+{
+ g_mutex_lock (&init_mutex);
+ if (!cert_db)
+ cert_db = g_object_new (E_TYPE_CERT_DB, NULL);
+ g_mutex_unlock (&init_mutex);
+
+ return cert_db;
+}
+
+void
+e_cert_db_shutdown (void)
+{
+ /* XXX */
+}
+
+/* searching for certificates */
+ECert *
+e_cert_db_find_cert_by_nickname (ECertDB *certdb,
+ const gchar *nickname,
+ GError **error)
+{
+ /* nsNSSShutDownPreventionLock locker;*/
+ CERTCertificate *cert = NULL;
+
+ /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));*/
+ cert = PK11_FindCertFromNickname ((gchar *) nickname, NULL);
+ if (!cert) {
+ cert = CERT_FindCertByNickname (CERT_GetDefaultCertDB (), (gchar *) nickname);
+ }
+
+ if (cert) {
+ /* PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n"));*/
+ ECert *ecert = e_cert_new (cert);
+ return ecert;
+ }
+ else {
+ set_nss_error (error);
+ return NULL;
+ }
+}
+
+#ifdef notyet
+ECert *
+e_cert_db_find_cert_by_key (ECertDB *certdb,
+ const gchar *db_key,
+ GError **error)
+{
+ /* nsNSSShutDownPreventionLock locker;*/
+ SECItem keyItem = {siBuffer, NULL, 0};
+ SECItem *dummy;
+ CERTIssuerAndSN issuerSN;
+ gulong moduleID,slotID;
+ CERTCertificate *cert;
+
+ if (!db_key) {
+ set_nss_error (error);
+ return NULL;
+ }
+
+ dummy = NSSBase64_DecodeBuffer (
+ NULL, &keyItem, db_key,
+ (PRUint32) PL_strlen (db_key));
+
+ /* someday maybe we can speed up the search using the moduleID and slotID*/
+ moduleID = NS_NSS_GET_LONG (keyItem.data);
+ slotID = NS_NSS_GET_LONG (&keyItem.data[NS_NSS_LONG]);
+
+ /* build the issuer/SN structure*/
+ issuerSN.serialNumber.len = NS_NSS_GET_LONG (&keyItem.data[NS_NSS_LONG *2]);
+ issuerSN.derIssuer.len = NS_NSS_GET_LONG (&keyItem.data[NS_NSS_LONG *3]);
+ issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG *4];
+ issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG *4+
+ issuerSN.serialNumber.len];
+
+ cert = CERT_FindCertByIssuerAndSN (CERT_GetDefaultCertDB (), &issuerSN);
+ PR_FREEIF (keyItem.data);
+ if (cert) {
+ ECert *ecert = e_cert_new (cert);
+ return e_cert;
+ }
+
+ set_nss_error (error);
+ return NULL;
+}
+
+GList *
+e_cert_db_get_cert_nicknames (ECertDB *certdb,
+ ECertType cert_type,
+ GError **error)
+{
+}
+
+ECert *
+e_cert_db_find_email_encryption_cert (ECertDB *certdb,
+ const gchar *nickname,
+ GError **error)
+{
+}
+
+ECert *
+e_cert_db_find_email_signing_cert (ECertDB *certdb,
+ const gchar *nickname,
+ GError **error)
+{
+}
+#endif
+
+ECert *
+e_cert_db_find_cert_by_email_address (ECertDB *certdb,
+ const gchar *email,
+ GError **error)
+{
+ /* nsNSSShutDownPreventionLock locker; */
+ ECert *cert;
+ CERTCertificate *any_cert;
+ CERTCertList *certlist;
+
+ any_cert = CERT_FindCertByNicknameOrEmailAddr (
+ CERT_GetDefaultCertDB (), (gchar *) email);
+
+ if (!any_cert) {
+ set_nss_error (error);
+ return NULL;
+ }
+
+ /* any_cert now contains a cert with the right subject,
+ * but it might not have the correct usage. */
+ certlist = CERT_CreateSubjectCertList (
+ NULL,
+ CERT_GetDefaultCertDB (),
+ &any_cert->derSubject,
+ PR_Now (), PR_TRUE);
+ if (!certlist) {
+ set_nss_error (error);
+ CERT_DestroyCertificate (any_cert);
+ return NULL;
+ }
+
+ if (SECSuccess != CERT_FilterCertListByUsage (
+ certlist, certUsageEmailRecipient, PR_FALSE)) {
+ set_nss_error (error);
+ CERT_DestroyCertificate (any_cert);
+ CERT_DestroyCertList (certlist);
+ return NULL;
+ }
+
+ if (CERT_LIST_END (CERT_LIST_HEAD (certlist), certlist)) {
+ set_nss_error (error);
+ CERT_DestroyCertificate (any_cert);
+ CERT_DestroyCertList (certlist);
+ return NULL;
+ }
+
+ cert = e_cert_new (CERT_DupCertificate (CERT_LIST_HEAD (certlist)->cert));
+
+ CERT_DestroyCertList (certlist);
+ CERT_DestroyCertificate (any_cert);
+
+ return cert;
+}
+
+static gboolean
+confirm_download_ca_cert (ECertDB *cert_db,
+ ECert *cert,
+ gboolean *trust_ssl,
+ gboolean *trust_email,
+ gboolean *trust_objsign)
+{
+ gboolean rv = FALSE;
+
+ *trust_ssl =
+ *trust_email =
+ *trust_objsign = FALSE;
+
+ g_signal_emit (
+ e_cert_db_peek (),
+ e_cert_db_signals[CONFIRM_CA_CERT_IMPORT], 0,
+ cert,
+ trust_ssl,
+ trust_email,
+ trust_objsign,
+ &rv);
+
+ return rv;
+}
+
+static gboolean
+handle_ca_cert_download (ECertDB *cert_db,
+ GList *certs,
+ GError **error)
+{
+ ECert *certToShow;
+ SECItem der;
+ gchar *raw_der = NULL;
+ CERTCertificate *tmpCert;
+
+ /* First thing we have to do is figure out which certificate
+ * we're gonna present to the user. The CA may have sent down
+ * a list of certs which may or may not be a chained list of
+ * certs. Until the day we can design some solid UI for the
+ * general case, we'll code to the > 90% case. That case is
+ * where a CA sends down a list that is a chain up to its root
+ * in either ascending or descending order. What we're gonna
+ * do is compare the first 2 entries, if the first was signed
+ * by the second, we assume the leaf cert is the first cert
+ * and display it. If the second cert was signed by the first
+ * cert, then we assume the first cert is the root and the
+ * last cert in the array is the leaf. In this case we
+ * display the last cert.
+ */
+
+ /* nsNSSShutDownPreventionLock locker;*/
+
+ if (certs == NULL) {
+ g_warning ("Didn't get any certs to import.");
+ return TRUE;
+ }
+ else if (certs->next == NULL) {
+ /* there's 1 cert */
+ certToShow = E_CERT (certs->data);
+ }
+ else {
+ /* there are multiple certs */
+ ECert *cert0;
+ ECert *cert1;
+ const gchar * cert0SubjectName;
+ const gchar * cert0IssuerName;
+ const gchar * cert1SubjectName;
+ const gchar * cert1IssuerName;
+
+ cert0 = E_CERT (certs->data);
+ cert1 = E_CERT (certs->next->data);
+
+ cert0IssuerName = e_cert_get_issuer_name (cert0);
+ cert0SubjectName = e_cert_get_subject_name (cert0);
+
+ cert1IssuerName = e_cert_get_issuer_name (cert1);
+ cert1SubjectName = e_cert_get_subject_name (cert1);
+
+ if (!strcmp (cert1IssuerName, cert0SubjectName)) {
+ /* In this case, the first cert in the list signed the second,
+ * so the first cert is the root. Let's display the last cert
+ * in the list. */
+ certToShow = E_CERT (g_list_last (certs)->data);
+ }
+ else if (!strcmp (cert0IssuerName, cert1SubjectName)) {
+ /* In this case the second cert has signed the first cert. The
+ * first cert is the leaf, so let's display it. */
+ certToShow = cert0;
+ } else {
+ /* It's not a chain, so let's just show the first one in the
+ * downloaded list. */
+ certToShow = cert0;
+ }
+ }
+
+ if (!certToShow) {
+ set_nss_error (error);
+ return FALSE;
+ }
+
+ if (!e_cert_get_raw_der (certToShow, &raw_der, &der.len)) {
+ set_nss_error (error);
+ return FALSE;
+ }
+
+ der.data = (guchar *) raw_der;
+
+ {
+ /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));*/
+ CERTCertDBHandle *certdb = CERT_GetDefaultCertDB ();
+ tmpCert = CERT_FindCertByDERCert (certdb, &der);
+ if (!tmpCert) {
+ tmpCert = CERT_NewTempCertificate (
+ certdb, &der,
+ NULL, PR_FALSE, PR_TRUE);
+ }
+ if (!tmpCert) {
+ g_warning ("Couldn't create cert from DER blob");
+ set_nss_error (error);
+ return FALSE;
+ }
+ }
+
+#if 0
+ CERTCertificateCleaner tmpCertCleaner (tmpCert);
+#endif
+
+ if (tmpCert->isperm) {
+ if (error && !*error)
+ *error = g_error_new_literal (E_CERTDB_ERROR, 0, _("Certificate already exists"));
+ return FALSE;
+ }
+ else {
+ gboolean trust_ssl, trust_email, trust_objsign;
+ gchar *nickname;
+ SECStatus srv;
+ CERTCertTrust trust;
+
+ if (!confirm_download_ca_cert (
+ cert_db, certToShow, &trust_ssl,
+ &trust_email, &trust_objsign)) {
+ set_nss_error (error);
+ return FALSE;
+ }
+
+ /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits));*/
+
+ nickname = CERT_MakeCANickname (tmpCert);
+
+ /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));*/
+
+ e_cert_trust_init (&trust);
+ e_cert_trust_set_valid_ca (&trust);
+ e_cert_trust_add_ca_trust (
+ &trust,
+ trust_ssl,
+ trust_email,
+ trust_objsign);
+
+ srv = CERT_AddTempCertToPerm (
+ tmpCert,
+ nickname,
+ &trust);
+
+ /* If we aren't logged into the token, then what *should*
+ * happen is the above call should fail, and we should
+ * authenticate and then try again. But see NSS bug #595861.
+ * With NSS 3.12.6 at least, the above call will fail, but
+ * it *will* have added the cert to the database, with
+ * random trust bits. We have to authenticate and then set
+ * the trust bits correctly. And calling
+ * CERT_AddTempCertToPerm() again doesn't work either -- it'll
+ * fail even though it arguably ought to succeed (which is
+ * probably another NSS bug).
+ * So if we get SEC_ERROR_TOKEN_NOT_LOGGED_IN, we first try
+ * CERT_ChangeCertTrust(), and if that doesn't work we hope
+ * we're on a fixed version of NSS and we try calling
+ * CERT_AddTempCertToPerm() again instead. */
+ if (srv != SECSuccess &&
+ PORT_GetError () == SEC_ERROR_TOKEN_NOT_LOGGED_IN &&
+ e_cert_db_login_to_slot (NULL, PK11_GetInternalKeySlot ())) {
+ srv = CERT_ChangeCertTrust (
+ CERT_GetDefaultCertDB (),
+ tmpCert, &trust);
+ if (srv != SECSuccess)
+ srv = CERT_AddTempCertToPerm (
+ tmpCert,
+ nickname,
+ &trust);
+ }
+ if (srv != SECSuccess) {
+ set_nss_error (error);
+ return FALSE;
+ }
+
+#if 0
+ /* Now it's time to add the rest of the certs we just downloaded.
+ * Since we didn't prompt the user about any of these certs, we
+ * won't set any trust bits for them. */
+ e_cert_trust_init (&trust);
+ e_cert_trust_set_valid_ca (&trust);
+ e_cert_trusts_add_ca_trust (&trust, 0, 0, 0);
+ for (PRUint32 i = 0; i < numCerts; i++) {
+ if (i == selCertIndex)
+ continue;
+
+ certToShow = do_QueryElementAt (x509Certs, i);
+ certToShow->GetRawDER (&der.len, (PRUint8 **) &der.data);
+
+ CERTCertificate *tmpCert2 =
+ CERT_NewTempCertificate (certdb, &der, nsnull, PR_FALSE, PR_TRUE);
+
+ if (!tmpCert2) {
+ NS_ASSERTION (0, "Couldn't create temp cert from DER blob\n");
+ continue; /* Let's try to import the rest of 'em */
+ }
+ nickname.Adopt (CERT_MakeCANickname (tmpCert2));
+ CERT_AddTempCertToPerm (
+ tmpCert2, NS_CONST_CAST (gchar *,nickname.get ()),
+ defaultTrust.GetTrust ());
+ CERT_DestroyCertificate (tmpCert2);
+ }
+#endif
+ return TRUE;
+ }
+}
+gboolean e_cert_db_change_cert_trust (CERTCertificate *cert, CERTCertTrust *trust)
+{
+ SECStatus srv;
+
+ srv = CERT_ChangeCertTrust (
+ CERT_GetDefaultCertDB (),
+ cert, trust);
+ if (srv != SECSuccess &&
+ PORT_GetError () == SEC_ERROR_TOKEN_NOT_LOGGED_IN &&
+ e_cert_db_login_to_slot (NULL, PK11_GetInternalKeySlot ()))
+ srv = CERT_ChangeCertTrust (
+ CERT_GetDefaultCertDB (),
+ cert, trust);
+
+ if (srv != SECSuccess) {
+ glong err = PORT_GetError ();
+ g_warning (
+ "CERT_ChangeCertTrust() failed: %s\n",
+ nss_error_to_string (err));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* deleting certificates */
+gboolean
+e_cert_db_delete_cert (ECertDB *certdb,
+ ECert *ecert)
+{
+ /* nsNSSShutDownPreventionLock locker;
+ * nsNSSCertificate *nssCert = NS_STATIC_CAST (nsNSSCertificate *, aCert); */
+
+ CERTCertificate *cert;
+
+ if (!e_cert_mark_for_deletion (ecert)) {
+ return FALSE;
+ }
+
+ cert = e_cert_get_internal_cert (ecert);
+ if (cert->slot && e_cert_get_cert_type (ecert) != E_CERT_USER) {
+ /* To delete a cert of a slot (builtin, most likely), mark it as
+ * completely untrusted. This way we keep a copy cached in the
+ * local database, and next time we try to load it off of the
+ * external token/slot, we'll know not to trust it. We don't
+ * want to do that with user certs, because a user may re-store
+ * the cert onto the card again at which point we *will* want to
+ * trust that cert if it chains up properly. */
+ CERTCertTrust trust;
+
+ e_cert_trust_init_with_values (&trust, 0, 0, 0);
+ return e_cert_db_change_cert_trust (cert, &trust);
+ }
+
+ return TRUE;
+}
+
+/* importing certificates */
+gboolean
+e_cert_db_import_certs (ECertDB *certdb,
+ gchar *data,
+ guint32 length,
+ ECertType cert_type,
+ GSList **imported_certs,
+ GError **error)
+{
+ /*nsNSSShutDownPreventionLock locker;*/
+ PRArenaPool *arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
+ GList *certs = NULL;
+ CERTDERCerts *certCollection = e_cert_db_get_certs_from_package (arena, data, length);
+ gint i;
+ gboolean rv;
+
+ if (!certCollection) {
+ set_nss_error (error);
+ PORT_FreeArena (arena, PR_FALSE);
+ return FALSE;
+ }
+
+ /* Now let's create some certs to work with */
+ 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) {
+ set_nss_error (error);
+ g_list_foreach (certs, (GFunc) g_object_unref, NULL);
+ g_list_free (certs);
+ PORT_FreeArena (arena, PR_FALSE);
+ return FALSE;
+ }
+ certs = g_list_append (certs, cert);
+ }
+ 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.*/
+ set_nss_error (error);
+ PORT_FreeArena (arena, PR_FALSE);
+ rv = FALSE;
+ }
+
+ g_list_foreach (certs, (GFunc) g_object_unref, NULL);
+ g_list_free (certs);
+ PORT_FreeArena (arena, PR_FALSE);
+ return rv;
+}
+
+gboolean
+e_cert_db_import_email_cert (ECertDB *certdb,
+ gchar *data,
+ guint32 length,
+ GSList **imported_certs,
+ GError **error)
+{
+ /*nsNSSShutDownPreventionLock locker;*/
+ SECStatus srv = SECFailure;
+ gboolean rv = TRUE;
+ CERTCertificate * cert;
+ SECItem **rawCerts;
+ gint numcerts;
+ gint i;
+ PRArenaPool *arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
+ CERTDERCerts *certCollection = e_cert_db_get_certs_from_package (arena, data, length);
+
+ if (!certCollection) {
+ set_nss_error (error);
+ PORT_FreeArena (arena, PR_FALSE);
+ return FALSE;
+ }
+
+ cert = CERT_NewTempCertificate (
+ CERT_GetDefaultCertDB (), certCollection->rawCerts,
+ (gchar *) NULL, PR_FALSE, PR_TRUE);
+ if (!cert) {
+ set_nss_error (error);
+ rv = FALSE;
+ goto loser;
+ }
+ numcerts = certCollection->numcerts;
+ rawCerts = (SECItem **) PORT_Alloc (sizeof (SECItem *) * numcerts);
+ if (!rawCerts) {
+ set_nss_error (error);
+ rv = FALSE;
+ goto loser;
+ }
+
+ for (i = 0; i < numcerts; i++) {
+ rawCerts[i] = &certCollection->rawCerts[i];
+ }
+
+ srv = CERT_ImportCerts (
+ CERT_GetDefaultCertDB (), certUsageEmailSigner,
+ numcerts, rawCerts, NULL, PR_TRUE, PR_FALSE,
+ NULL);
+ if (srv != SECSuccess) {
+ 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)
+ CERT_DestroyCertificate (cert);
+ if (arena)
+ PORT_FreeArena (arena, PR_TRUE);
+ return rv;
+}
+
+static gchar *
+default_nickname (CERTCertificate *cert)
+{
+ /* nsNSSShutDownPreventionLock locker; */
+ gchar *username = NULL;
+ gchar *caname = NULL;
+ gchar *nickname = NULL;
+ gchar *tmp = NULL;
+ gint count;
+ const gchar *nickFmt = NULL;
+ CERTCertificate *dummycert;
+ PK11SlotInfo *slot = NULL;
+ CK_OBJECT_HANDLE keyHandle;
+
+ CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB ();
+
+ username = CERT_GetCommonName (&cert->subject);
+ if (username == NULL)
+ username = PL_strdup ("");
+
+ if (username == NULL)
+ goto loser;
+
+ caname = CERT_GetOrgName (&cert->issuer);
+ if (caname == NULL)
+ caname = PL_strdup ("");
+
+ if (caname == NULL)
+ goto loser;
+
+ count = 1;
+
+ nickFmt = "%1$s's %2$s ID";
+
+ nickname = PR_smprintf (nickFmt, username, caname);
+ /*
+ * We need to see if the private key exists on a token, if it does
+ * then we need to check for nicknames that already exist on the smart
+ * card.
+ */
+ slot = PK11_KeyForCertExists (cert, &keyHandle, NULL);
+ if (slot == NULL) {
+ goto loser;
+ }
+ if (!PK11_IsInternal (slot)) {
+ tmp = PR_smprintf ("%s:%s", PK11_GetTokenName (slot), nickname);
+ PR_Free (nickname);
+ nickname = tmp;
+ tmp = NULL;
+ }
+ tmp = nickname;
+ while (1) {
+ if (count > 1) {
+ nickname = PR_smprintf ("%s #%d", tmp, count);
+ }
+
+ if (nickname == NULL)
+ goto loser;
+
+ if (PK11_IsInternal (slot)) {
+ /* look up the nickname to make sure it isn't in use already */
+ dummycert = CERT_FindCertByNickname (defaultcertdb, nickname);
+
+ } else {
+ /*
+ * Check the cert against others that already live on the smart
+ * card.
+ */
+ dummycert = PK11_FindCertFromNickname (nickname, NULL);
+ if (dummycert != NULL) {
+ /*
+ * Make sure the subject names are different.
+ */
+ if (CERT_CompareName (&cert->subject, &dummycert->subject) == SECEqual) {
+ /*
+ * There is another certificate with the same nickname and
+ * the same subject name on the smart card, so let's use this
+ * nickname.
+ */
+ CERT_DestroyCertificate (dummycert);
+ dummycert = NULL;
+ }
+ }
+ }
+ if (dummycert == NULL)
+ goto done;
+
+ /* found a cert, destroy it and loop */
+ CERT_DestroyCertificate (dummycert);
+ if (tmp != nickname) PR_Free (nickname);
+ count++;
+ } /* end of while (1) */
+
+ loser:
+ if (nickname) {
+ PR_Free (nickname);
+ }
+ nickname = NULL;
+ done:
+ if (caname) {
+ PR_Free (caname);
+ }
+ if (username) {
+ PR_Free (username);
+ }
+ if (slot != NULL) {
+ PK11_FreeSlot (slot);
+ if (nickname != NULL) {
+ tmp = nickname;
+ nickname = strchr (tmp, ':');
+ if (nickname != NULL) {
+ nickname++;
+ nickname = PL_strdup (nickname);
+ PR_Free (tmp);
+ tmp = NULL;
+ } else {
+ nickname = tmp;
+ tmp = NULL;
+ }
+ }
+ }
+ PR_FREEIF (tmp);
+ return (nickname);
+}
+
+gboolean
+e_cert_db_import_user_cert (ECertDB *certdb,
+ gchar *data,
+ guint32 length,
+ GError **error)
+{
+ /* nsNSSShutDownPreventionLock locker;*/
+ PK11SlotInfo *slot;
+ gchar * nickname = NULL;
+ gboolean rv = FALSE;
+ gint numCACerts;
+ SECItem *CACerts;
+ CERTDERCerts * collectArgs;
+ PRArenaPool *arena;
+ CERTCertificate * cert = NULL;
+
+ arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ set_nss_error (error);
+ goto loser;
+ }
+
+ collectArgs = e_cert_db_get_certs_from_package (arena, data, length);
+ if (!collectArgs) {
+ set_nss_error (error);
+ goto loser;
+ }
+
+ cert = CERT_NewTempCertificate (
+ CERT_GetDefaultCertDB (), collectArgs->rawCerts,
+ (gchar *) NULL, PR_FALSE, PR_TRUE);
+ if (!cert) {
+ set_nss_error (error);
+ goto loser;
+ }
+
+ slot = PK11_KeyForCertExists (cert, NULL, NULL);
+ if (slot == NULL) {
+ set_nss_error (error);
+ goto loser;
+ }
+ PK11_FreeSlot (slot);
+
+ /* pick a nickname for the cert */
+ if (cert->nickname) {
+ /* sigh, we need a call to look up other certs with this subject and
+ * identify nicknames from them. We can no longer walk down internal
+ * database structures rjr */
+ nickname = cert->nickname;
+ }
+ else {
+ nickname = default_nickname (cert);
+ }
+
+ /* user wants to import the cert */
+ slot = PK11_ImportCertForKey (cert, nickname, NULL);
+ if (!slot) {
+ set_nss_error (error);
+ goto loser;
+ }
+ PK11_FreeSlot (slot);
+ numCACerts = collectArgs->numcerts - 1;
+
+ if (numCACerts) {
+ CACerts = collectArgs->rawCerts + 1;
+ if (!CERT_ImportCAChain (CACerts, numCACerts, certUsageUserCertImport)) {
+ rv = TRUE;
+ }
+ }
+
+ loser:
+ if (arena) {
+ PORT_FreeArena (arena, PR_FALSE);
+ }
+ if (cert) {
+ CERT_DestroyCertificate (cert);
+ }
+ return rv;
+}
+
+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
+ * for server certs anyway */
+ return FALSE;
+}
+
+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;
+ gint fd;
+ struct stat sb;
+ gchar *buf;
+ gint bytes_read;
+
+ switch (cert_type) {
+ case E_CERT_CA:
+ case E_CERT_CONTACT:
+ case E_CERT_SITE:
+ /* good */
+ break;
+
+ default:
+ /* not supported (yet) */
+ set_nss_error (error);
+ return FALSE;
+ }
+
+ fd = g_open (file_path, O_RDONLY | O_BINARY, 0);
+ if (fd == -1) {
+ set_nss_error (error);
+ return FALSE;
+ }
+
+ if (-1 == fstat (fd, &sb)) {
+ set_nss_error (error);
+ close (fd);
+ return FALSE;
+ }
+
+ buf = g_malloc (sb.st_size);
+ if (!buf) {
+ set_nss_error (error);
+ close (fd);
+ return FALSE;
+ }
+
+ bytes_read = read (fd, buf, sb.st_size);
+
+ close (fd);
+
+ if (bytes_read != sb.st_size) {
+ set_nss_error (error);
+ rv = FALSE;
+ }
+ else {
+ printf ("importing %d bytes from '%s'\n", bytes_read, file_path);
+
+ switch (cert_type) {
+ case E_CERT_CA:
+ 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, imported_certs, error);
+ break;
+
+ case E_CERT_CONTACT:
+ rv = e_cert_db_import_email_cert (cert_db, buf, bytes_read, imported_certs, error);
+ break;
+
+ default:
+ rv = FALSE;
+ break;
+ }
+ }
+
+ g_free (buf);
+ return rv;
+}
+
+gboolean
+e_cert_db_import_pkcs12_file (ECertDB *cert_db,
+ const gchar *file_path,
+ GError **error)
+{
+ EPKCS12 *pkcs12 = e_pkcs12_new ();
+ GError *e = NULL;
+
+ if (!e_pkcs12_import_from_file (pkcs12, file_path, &e)) {
+ g_propagate_error (error, e);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#ifdef notyet
+gboolean
+e_cert_db_export_pkcs12_file (ECertDB *cert_db,
+ const gchar *file_path,
+ GList *certs,
+ GError **error)
+{
+}
+#endif
+
+gboolean
+e_cert_db_login_to_slot (ECertDB *cert_db,
+ PK11SlotInfo *slot)
+{
+ if (PK11_NeedLogin (slot)) {
+ PK11_Logout (slot);
+
+ if (PK11_NeedUserInit (slot)) {
+ gchar *pwd;
+ gboolean rv = FALSE;
+
+ printf ("initializing slot password\n");
+
+ g_signal_emit (
+ e_cert_db_peek (),
+ e_cert_db_signals[PK11_CHANGE_PASSWD], 0,
+ NULL,
+ &pwd,
+ &rv);
+
+ if (!rv)
+ return FALSE;
+
+ /* the user needs to specify the initial password */
+ PK11_InitPin (slot, "", pwd);
+ }
+
+ PK11_SetPasswordFunc (pk11_password);
+ if (PK11_Authenticate (slot, PR_TRUE, NULL) != SECSuccess) {
+ printf (
+ "PK11_Authenticate failed (err = %d/%d)\n",
+ PORT_GetError (), PORT_GetError () + 0x2000);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}