gee
oldstatus
2005-09-19, Nathan Walp
* @file ssl-nss.c Mozilla NSS SSL plugin. * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org> * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define SSL_NSS_PLUGIN_ID "ssl-nss" #undef HAVE_LONG_LONG /* Make Mozilla less angry. If angry, Mozilla SMASH! */ #include <private/pprio.h> #define GAIM_SSL_NSS_DATA(gsc) ((GaimSslNssData *)gsc->private_data) static const PRIOMethods *_nss_methods = NULL; static PRDescIdentity _identity; PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); /* TODO: Fix this so autoconf does the work trying to find this lib. */ lib = g_strdup(BR_LIBDIR("/libnssckbi.so")); lib = g_strdup("nssckbi.dll"); SECMOD_AddNewModule("Builtins", lib, 0, 0); _identity = PR_GetUniqueIdentity("Gaim"); _nss_methods = PR_GetDefaultIOMethods(); ssl_auth_cert(void *arg, PRFileDesc *socket, PRBool checksig, cert = SSL_PeerCertificate(socket); pinArg = SSL_RevealPinArg(socket); status = CERT_VerifyCertNow((CERTCertDBHandle *)arg, cert, checksig, certUsageSSLClient, pinArg); if (status != SECSuccess) { gaim_debug_error("nss", "CERT_VerifyCertNow failed\n"); CERT_DestroyCertificate(cert); CERT_DestroyCertificate(cert); ssl_bad_cert(void *arg, PRFileDesc *socket) SECStatus status = SECFailure; *(PRErrorCode *)arg = err = PORT_GetError(); case SEC_ERROR_INVALID_AVA: case SEC_ERROR_INVALID_TIME: case SEC_ERROR_BAD_SIGNATURE: case SEC_ERROR_EXPIRED_CERTIFICATE: case SEC_ERROR_UNKNOWN_ISSUER: case SEC_ERROR_UNTRUSTED_CERT: case SEC_ERROR_CERT_VALID: case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: case SEC_ERROR_CRL_EXPIRED: case SEC_ERROR_CRL_BAD_SIGNATURE: case SEC_ERROR_EXTENSION_VALUE_INVALID: case SEC_ERROR_CA_CERT_INVALID: case SEC_ERROR_CERT_USAGES_INVALID: case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION: gaim_debug_error("nss", "Bad certificate: %d\n"); ssl_nss_connect_cb(gpointer data, gint source, GaimInputCondition cond) GaimSslConnection *gsc = (GaimSslConnection *)data; GaimSslNssData *nss_data = g_new0(GaimSslNssData, 1); PRSocketOptionData socket_opt; gsc->private_data = nss_data; nss_data->fd = PR_ImportTCPSocket(gsc->fd); if (nss_data->fd == NULL) gaim_debug_error("nss", "nss_data->fd == NULL!\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, GAIM_SSL_CONNECT_FAILED, gsc->connect_cb_data); gaim_ssl_close((GaimSslConnection *)gsc); socket_opt.option = PR_SockOpt_Nonblocking; socket_opt.value.non_blocking = PR_FALSE; PR_SetSocketOption(nss_data->fd, &socket_opt); nss_data->in = SSL_ImportFD(NULL, nss_data->fd); if (nss_data->in == NULL) gaim_debug_error("nss", "nss_data->in == NUL!\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, GAIM_SSL_CONNECT_FAILED, gsc->connect_cb_data); gaim_ssl_close((GaimSslConnection *)gsc); SSL_OptionSet(nss_data->in, SSL_SECURITY, PR_TRUE); SSL_OptionSet(nss_data->in, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); SSL_AuthCertificateHook(nss_data->in, (SSLAuthCertificate)ssl_auth_cert, (void *)CERT_GetDefaultCertDB()); SSL_BadCertHook(nss_data->in, (SSLBadCertHandler)ssl_bad_cert, NULL); SSL_SetURL(nss_data->in, gsc->host); SSL_ResetHandshake(nss_data->in, PR_FALSE); if (SSL_ForceHandshake(nss_data->in)) gaim_debug_error("nss", "Handshake failed\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, GAIM_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); gsc->connect_cb(gsc->connect_cb_data, gsc, cond); ssl_nss_close(GaimSslConnection *gsc) GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); if (nss_data->in) PR_Close(nss_data->in); /* if (nss_data->fd) PR_Close(nss_data->fd); */ ssl_nss_read(GaimSslConnection *gsc, void *data, size_t len) GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); return PR_Read(nss_data->in, data, len); ssl_nss_write(GaimSslConnection *gsc, const void *data, size_t len) GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); return PR_Write(nss_data->in, data, len); static GaimSslOps ssl_ops = plugin_load(GaimPlugin *plugin) if (!gaim_ssl_get_ops()) { gaim_ssl_set_ops(&ssl_ops); /* Init NSS now, so others can use it even if sslconn never does */ plugin_unload(GaimPlugin *plugin) if (gaim_ssl_get_ops() == &ssl_ops) { static GaimPluginInfo info = GAIM_PLUGIN_STANDARD, /**< type */ NULL, /**< ui_requirement */ GAIM_PLUGIN_FLAG_INVISIBLE, /**< flags */ NULL, /**< dependencies */ GAIM_PRIORITY_DEFAULT, /**< priority */ SSL_NSS_PLUGIN_ID, /**< id */ N_("Provides SSL support through Mozilla NSS."), N_("Provides SSL support through Mozilla NSS."), "Christian Hammond <chipx86@gnupdate.org>", GAIM_WEBSITE, /**< homepage */ plugin_load, /**< load */ plugin_unload, /**< unload */ init_plugin(GaimPlugin *plugin) GAIM_INIT_PLUGIN(ssl_nss, init_plugin, info)