Mercurial > pidgin
changeset 6703:36897b9e009f
[gaim-migrate @ 7229]
Forgot the SSL wrapper code.
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Tue, 02 Sep 2003 04:43:28 +0000 |
parents | 302ee2792e91 |
children | 471eed8124d5 |
files | src/sslconn.c src/sslconn.h |
diffstat | 2 files changed, 474 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sslconn.c Tue Sep 02 04:43:28 2003 +0000 @@ -0,0 +1,357 @@ +/** + * @file sslconn.c SSL API + * @ingroup core + * + * gaim + * + * 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 + */ +#include "internal.h" + +#include "debug.h" +#include "sslconn.h" + +#ifdef HAVE_NSS +# include <nspr.h> +# include <nss.h> +# include <pk11func.h> +# include <prio.h> +# include <secerr.h> +# include <secmod.h> +# include <ssl.h> +# include <sslerr.h> +# include <sslproto.h> + +typedef struct +{ + char *host; + int port; + void *user_data; + GaimSslInputFunction input_func; + + int fd; + int inpa; + + PRFileDesc *nss_fd; + PRFileDesc *nss_in; + +} GaimSslData; + +static gboolean _nss_initialized = FALSE; +static const PRIOMethods *_nss_methods = NULL; +static PRDescIdentity _identity; + +static void +destroy_ssl_data(GaimSslData *data) +{ + if (data->inpa) gaim_input_remove(data->inpa); + if (data->nss_in) PR_Close(data->nss_in); + if (data->nss_fd) PR_Close(data->nss_fd); + if (data->fd) close(data->fd); + + if (data->host != NULL) + g_free(data->host); + + g_free(data); +} + +static void +init_nss(void) +{ + if (_nss_initialized) + return; + + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + NSS_NoDB_Init(NULL); + + /* TODO: Fix this so autoconf does the work trying to find this lib. */ + SECMOD_AddNewModule("Builtins", LIBDIR "/libnssckbi.so", 0, 0); + NSS_SetDomesticPolicy(); + + _identity = PR_GetUniqueIdentity("Gaim"); + _nss_methods = PR_GetDefaultIOMethods(); + + _nss_initialized = TRUE; +} + +static SECStatus +ssl_auth_cert(void *arg, PRFileDesc *socket, PRBool checksig, PRBool is_server) +{ + return SECSuccess; + +#if 0 + CERTCertificate *cert; + void *pinArg; + SECStatus status; + + cert = SSL_PeerCertificate(socket); + pinArg = SSL_RevealPinArg(socket); + + status = CERT_VerifyCertNow((CERTCertDBHandle *)arg, cert, checksig, + certUsageSSLClient, pinArg); + + if (status != SECSuccess) { + gaim_debug(GAIM_DEBUG_ERROR, "msn", "CERT_VerifyCertNow failed\n"); + CERT_DestroyCertificate(cert); + return status; + } + + CERT_DestroyCertificate(cert); + return SECSuccess; +#endif +} + +SECStatus +ssl_bad_cert(void *arg, PRFileDesc *socket) +{ + SECStatus status = SECFailure; + PRErrorCode err; + + if (arg == NULL) + return status; + + *(PRErrorCode *)arg = err = PORT_GetError(); + + switch (err) + { + 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: + status = SECSuccess; + break; + + default: + status = SECFailure; + break; + } + + gaim_debug(GAIM_DEBUG_ERROR, "msn", + "Bad certificate: %d\n"); + + return status; +} + +static void +input_func(gpointer data, gint source, GaimInputCondition cond) +{ + GaimSslData *ssl_data = (GaimSslData *)data; + char *cp, *ip, *sp; + int op, kp0, kp1; + int result; + + result = SSL_SecurityStatus(ssl_data->nss_in, &op, &cp, &kp0, + &kp1, &ip, &sp); + + gaim_debug(GAIM_DEBUG_MISC, "msn", + "bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" + "subject DN: %s\n" + "issuer DN: %s\n", + cp, kp1, kp0, op, sp, ip); + + PR_Free(cp); + PR_Free(ip); + PR_Free(sp); + + ssl_data->input_func(ssl_data->user_data, (GaimSslConnection *)ssl_data, + cond); +} + +static void +ssl_connect_cb(gpointer data, gint source, GaimInputCondition cond) +{ + PRSocketOptionData socket_opt; + GaimSslData *ssl_data = (GaimSslData *)data; + + if (!_nss_initialized) + init_nss(); + + ssl_data->fd = source; + + ssl_data->nss_fd = PR_ImportTCPSocket(ssl_data->fd); + + if (ssl_data->nss_fd == NULL) + { + gaim_debug(GAIM_DEBUG_ERROR, "ssl", "nss_fd == NULL!\n"); + + destroy_ssl_data(ssl_data); + + return; + } + + socket_opt.option = PR_SockOpt_Nonblocking; + socket_opt.value.non_blocking = PR_FALSE; + + PR_SetSocketOption(ssl_data->nss_fd, &socket_opt); + + ssl_data->nss_in = SSL_ImportFD(NULL, ssl_data->nss_fd); + + if (ssl_data->nss_in == NULL) + { + gaim_debug(GAIM_DEBUG_ERROR, "ssl", "nss_in == NUL!\n"); + + destroy_ssl_data(ssl_data); + + return; + } + + SSL_OptionSet(ssl_data->nss_in, SSL_SECURITY, PR_TRUE); + SSL_OptionSet(ssl_data->nss_in, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); + + SSL_AuthCertificateHook(ssl_data->nss_in, + (SSLAuthCertificate)ssl_auth_cert, + (void *)CERT_GetDefaultCertDB()); + SSL_BadCertHook(ssl_data->nss_in, (SSLBadCertHandler)ssl_bad_cert, NULL); + + SSL_SetURL(ssl_data->nss_in, ssl_data->host); + + SSL_ResetHandshake(ssl_data->nss_in, PR_FALSE); + + if (SSL_ForceHandshake(ssl_data->nss_in)) + { + gaim_debug(GAIM_DEBUG_ERROR, "ssl", "Handshake failed\n"); + + destroy_ssl_data(ssl_data); + + return; + } + +#if 0 + ssl_data->input_func(ssl_data->user_data, (GaimSslConnection *)ssl_data, + cond); +#endif + + input_func(ssl_data, source, cond); +} +#endif /* HAVE_NSS */ + +gboolean +gaim_ssl_is_supported(void) +{ +#ifdef HAVE_NSS + return TRUE; +#else + return FALSE; +#endif +} + +GaimSslConnection * +gaim_ssl_connect(GaimAccount *account, const char *host, int port, + GaimSslInputFunction func, void *data) +{ +#ifdef HAVE_NSS + int i; + GaimSslData *ssl_data; + + g_return_val_if_fail(host != NULL, NULL); + g_return_val_if_fail(port != 0 && port != -1, NULL); + g_return_val_if_fail(func != NULL, NULL); + g_return_val_if_fail(gaim_ssl_is_supported(), NULL); + + ssl_data = g_new0(GaimSslData, 1); + + ssl_data->host = g_strdup(host); + ssl_data->port = port; + ssl_data->user_data = data; + ssl_data->input_func = func; + + i = gaim_proxy_connect(account, host, port, ssl_connect_cb, ssl_data); + + if (i < 0) + { + g_free(ssl_data->host); + g_free(ssl_data); + + return NULL; + } + + return (GaimSslConnection)ssl_data; +#else + g_return_val_if_fail(gaim_ssl_is_supported(), -1); +#endif +} + +void +gaim_ssl_close(GaimSslConnection *gsc) +{ + g_return_if_fail(gsc != NULL); + +#ifdef HAVE_NSS + destroy_ssl_data((GaimSslData *)gsc); +#endif +} + +size_t +gaim_ssl_read(GaimSslConnection *gsc, void *data, size_t len) +{ +#ifdef HAVE_NSS + GaimSslData *ssl_data = (GaimSslData *)gsc; + + g_return_val_if_fail(gsc != NULL, 0); + g_return_val_if_fail(data != NULL, 0); + g_return_val_if_fail(len > 0, 0); + + return PR_Read(ssl_data->nss_in, data, len); +#else + return 0; +#endif +} + +size_t +gaim_ssl_write(GaimSslConnection *gsc, const void *data, size_t len) +{ +#ifdef HAVE_NSS + GaimSslData *ssl_data = (GaimSslData *)gsc; + + g_return_val_if_fail(gsc != NULL, 0); + g_return_val_if_fail(data != NULL, 0); + g_return_val_if_fail(len > 0, 0); + + return PR_Write(ssl_data->nss_in, data, len); +#else + return 0; +#endif +} + +void +gaim_ssl_init(void) +{ +} + +void +gaim_ssl_uninit(void) +{ + if (!_nss_initialized) + return; + +#ifdef HAVE_NSS + PR_Cleanup(); +#endif + + _nss_initialized = FALSE; + _nss_methods = NULL; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sslconn.h Tue Sep 02 04:43:28 2003 +0000 @@ -0,0 +1,117 @@ +/** + * @file sslconn.h SSL API + * @ingroup core + * + * gaim + * + * 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 + */ +#ifndef _GAIM_SSL_H_ +#define _GAIM_SSL_H_ + +#include "proxy.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GAIM_SSL_DEFAULT_PORT 443 + +typedef void *GaimSslConnection; +typedef void (*GaimSslInputFunction)(gpointer, GaimSslConnection *, + GaimInputCondition); + +/**************************************************************************/ +/** @name SSL API */ +/**************************************************************************/ +/*@{*/ + +/** + * Returns whether or not SSL is currently supported. + * + * @return TRUE if SSL is supported, or FALSE otherwise. + */ +gboolean gaim_ssl_is_supported(void); + +/** + * Makes a SSL connection to the specified host and port. + * + * @param account The account making the connection. + * @param host The destination host. + * @param port The destination port. + * @param func The SSL input handler function. + * @param data User-defined data. + * + * @return The SSL connection handle. + */ +GaimSslConnection *gaim_ssl_connect(GaimAccount *account, const char *host, + int port, GaimSslInputFunction func, + void *data); + +/** + * Closes a SSL connection. + * + * @param gsc The SSL connection to close. + */ +void gaim_ssl_close(GaimSslConnection *gsc); + +/** + * Reads data from an SSL connection. + * + * @param gsc The SSL connection handle. + * @param buffer The destination buffer. + * @param len The maximum number of bytes to read. + * + * @return The number of bytes read. + */ +size_t gaim_ssl_read(GaimSslConnection *gsc, void *data, size_t len); + +/** + * Writes data to an SSL connection. + * + * @param gsc The SSL connection handle. + * @param data The data to write. + * @param len The length of the data to write. + * + * @return The number of bytes written. + */ +size_t gaim_ssl_write(GaimSslConnection *gsc, const void *data, size_t len); + +/*@}*/ + +/**************************************************************************/ +/** @name Subsystem API */ +/**************************************************************************/ +/*@{*/ + +/** + * Initializes the SSL subsystem. + */ +void gaim_ssl_init(void); + +/** + * Uninitializes the SSL subsystem. + */ +void gaim_ssl_uninit(void); + +/*@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _GAIM_SSL_H_ */