Mercurial > pidgin
diff src/sslconn.c @ 6738:6c95f01aaf49
[gaim-migrate @ 7270]
Added optional GNUTLS support, which will also be used as a fallback if
Mozilla NSS is not installed.
committer: Tailor Script <tailor@pidgin.im>
| author | Christian Hammond <chipx86@chipx86.com> |
|---|---|
| date | Thu, 04 Sep 2003 06:19:25 +0000 |
| parents | b0913ab92893 |
| children | 57a24492434b |
line wrap: on
line diff
--- a/src/sslconn.c Thu Sep 04 05:36:09 2003 +0000 +++ b/src/sslconn.c Thu Sep 04 06:19:25 2003 +0000 @@ -25,235 +25,41 @@ #include "debug.h" #include "sslconn.h" +/* Pre-installed SSL op functions. */ #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; +GaimSslOps *gaim_ssl_nss_get_ops(); #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); +#ifdef HAVE_GNUTLS +GaimSslOps *gaim_ssl_gnutls_get_ops(); #endif - input_func(ssl_data, source, cond); + +static gboolean _ssl_initialized = FALSE; +static GaimSslOps *_ssl_ops = NULL; + +static gboolean +ssl_init(void) +{ + GaimSslOps *ops = gaim_ssl_get_ops(); + gboolean success = FALSE; + + if (_ssl_initialized) + return FALSE; + + if (ops != NULL && ops->init != NULL) + success = ops->init(); + + _ssl_initialized = success; + + return success; } -#endif /* HAVE_NSS */ gboolean gaim_ssl_is_supported(void) { -#ifdef HAVE_NSS - return TRUE; +#ifdef HAVE_SSL + return (gaim_ssl_get_ops() != NULL); #else return FALSE; #endif @@ -263,95 +69,138 @@ gaim_ssl_connect(GaimAccount *account, const char *host, int port, GaimSslInputFunction func, void *data) { -#ifdef HAVE_NSS + GaimSslConnection *gsc; + GaimSslOps *ops; 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); + ops = gaim_ssl_get_ops(); + + g_return_val_if_fail(ops != NULL, NULL); + g_return_val_if_fail(ops->connect_cb != NULL, NULL); - ssl_data->host = g_strdup(host); - ssl_data->port = port; - ssl_data->user_data = data; - ssl_data->input_func = func; + if (!_ssl_initialized) + { + if (!ssl_init()) + return NULL; + } - i = gaim_proxy_connect(account, host, port, ssl_connect_cb, ssl_data); + gsc = g_new0(GaimSslConnection, 1); + + gsc->host = g_strdup(host); + gsc->port = port; + gsc->user_data = data; + gsc->input_func = func; + + i = gaim_proxy_connect(account, host, port, ops->connect_cb, gsc); if (i < 0) { - g_free(ssl_data->host); - g_free(ssl_data); + g_free(gsc->host); + g_free(gsc); return NULL; } - return (GaimSslConnection)ssl_data; -#else - return GINT_TO_POINTER(-1); -#endif + return (GaimSslConnection *)gsc; } void gaim_ssl_close(GaimSslConnection *gsc) { + GaimSslOps *ops; + g_return_if_fail(gsc != NULL); -#ifdef HAVE_NSS - destroy_ssl_data((GaimSslData *)gsc); -#endif + ops = gaim_ssl_get_ops(); + + if (gsc->inpa) + gaim_input_remove(gsc->inpa); + + if (ops != NULL && ops->close != NULL) + ops->close(gsc); + + if (gsc->fd) + close(gsc->fd); + + if (gsc->host != NULL) + g_free(gsc->host); + + g_free(gsc); } size_t gaim_ssl_read(GaimSslConnection *gsc, void *data, size_t len) { -#ifdef HAVE_NSS - GaimSslData *ssl_data = (GaimSslData *)gsc; + GaimSslOps *ops; 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 + ops = gaim_ssl_get_ops(); + + if (ops != NULL && ops->read != NULL) + return ops->read(gsc, data, len); + return 0; -#endif } size_t gaim_ssl_write(GaimSslConnection *gsc, const void *data, size_t len) { -#ifdef HAVE_NSS - GaimSslData *ssl_data = (GaimSslData *)gsc; + GaimSslOps *ops; 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 + ops = gaim_ssl_get_ops(); + + if (ops != NULL && ops->write != NULL) + return ops->write(gsc, data, len); + return 0; -#endif +} + +void +gaim_ssl_set_ops(GaimSslOps *ops) +{ + _ssl_ops = ops; +} + +GaimSslOps * +gaim_ssl_get_ops(void) +{ + return _ssl_ops; } void gaim_ssl_init(void) { +#if defined(HAVE_NSS) + gaim_ssl_set_ops(gaim_ssl_nss_get_ops()); +#elif defined(HAVE_GNUTLS) + gaim_ssl_set_ops(gaim_ssl_gnutls_get_ops()); +#endif } void gaim_ssl_uninit(void) { -#ifdef HAVE_NSS - if (!_nss_initialized) + GaimSslOps *ops; + + if (!_ssl_initialized) return; - PR_Cleanup(); + ops = gaim_ssl_get_ops(); - _nss_initialized = FALSE; - _nss_methods = NULL; -#endif + if (ops != NULL && ops->uninit != NULL) + ops->uninit(); + + _ssl_initialized = FALSE; }
