From bdd44eb0ab7e6ee080989c672ce6deeffae987c2 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 13 Sep 2008 15:06:35 +0200 Subject: [PATCH] TLS/SSL support: core files. Contains support for both OpenSSL and GNU TLS. Certificate Authentification is not yet supported. --- src/ngircd/conf-ssl.h | 37 +++ src/ngircd/conn-ssl.c | 706 ++++++++++++++++++++++++++++++++++++++++++ src/ngircd/conn-ssl.h | 28 ++ 3 files changed, 771 insertions(+) create mode 100644 src/ngircd/conf-ssl.h create mode 100644 src/ngircd/conn-ssl.c create mode 100644 src/ngircd/conn-ssl.h diff --git a/src/ngircd/conf-ssl.h b/src/ngircd/conf-ssl.h new file mode 100644 index 00000000..35ba28f4 --- /dev/null +++ b/src/ngircd/conf-ssl.h @@ -0,0 +1,37 @@ +/* + * ngIRCd -- The Next Generation IRC Daemon + * SSL defines. + */ + +#ifndef conf_ssl_h +#define conf_ssl_h + +#ifdef HAVE_LIBSSL +#define SSL_SUPPORT +#include +#endif +#ifdef HAVE_LIBGNUTLS +#define SSL_SUPPORT +#include +#endif + +#ifdef SSL_SUPPORT +struct ConnSSL_State { +#ifdef HAVE_LIBSSL + SSL *ssl; +#endif +#ifdef HAVE_LIBGNUTLS + gnutls_session_t gnutls_session; + void *cookie; /* pointer to server configuration structure (for outgoing connections), or NULL. */ +#endif +}; + + +bool +ConnSSL_InitLibrary(void); +#else +static inline bool +ConnSSL_InitLibrary(void) { return true; } +#endif /* SSL_SUPPORT */ +#endif /* conf_ssl_h */ +/* -eof- */ diff --git a/src/ngircd/conn-ssl.c b/src/ngircd/conn-ssl.c new file mode 100644 index 00000000..ae9595f9 --- /dev/null +++ b/src/ngircd/conn-ssl.c @@ -0,0 +1,706 @@ +/* + * ngIRCd -- The Next Generation IRC Daemon + * + * SSL wrapper functions. + * Copyright (c) 2005-2008 Florian Westphal + */ + +#include "portab.h" +#include "imp.h" +#include "conf-ssl.h" + +#ifdef SSL_SUPPORT + +#include "io.h" +#include +#include +#include +#include +#include + +#define CONN_MODULE +#include "conn.h" +#include "conf.h" +#include "conn-func.h" +#include "conn-ssl.h" +#include "log.h" + +#include "exp.h" +#include "defines.h" + +extern struct SSLOptions Conf_SSLOptions; + +#ifdef HAVE_LIBSSL +#include +#include + +static SSL_CTX * ssl_ctx; +static DH *dh_params; + +static bool ConnSSL_LoadServerKey_openssl PARAMS(( SSL_CTX *c )); +#endif + +#ifdef HAVE_LIBGNUTLS +#include +#include +#include +#include +#include + +#define DH_BITS 1024 +static gnutls_certificate_credentials_t x509_cred; +static gnutls_dh_params_t dh_params; + +static bool ConnSSL_LoadServerKey_gnutls PARAMS(( void )); +#endif + +static bool ConnSSL_Init_SSL PARAMS(( CONNECTION *c )); +static int ConnectAccept PARAMS(( CONNECTION *c, bool connect )); +static int ConnSSL_HandleError PARAMS(( CONNECTION *c, const int code, const char *fname )); + +#ifdef HAVE_LIBGNUTLS +static char * openreadclose(const char *name, size_t *len) +{ + char *buf = NULL; + struct stat s; + ssize_t br; + int fd = open(name, O_RDONLY); + if (fd < 0) { + Log(LOG_ERR, "Could not open %s: %s", name, strerror(errno)); + return NULL; + } + if (fstat(fd, &s)) { + Log(LOG_ERR, "Could not fstat %s: %s", name, strerror(errno)); + goto out; + } + if (!S_ISREG(s.st_mode)) { + Log(LOG_ERR, "%s: Not a regular file", name); + goto out; + } + if (s.st_size <= 0) { + Log(LOG_ERR, "%s: invalid file length (size %ld <= 0)", name, (long) s.st_size); + goto out; + } + buf = malloc(s.st_size); + if (!buf) { + Log(LOG_ERR, "Could not malloc %lu bytes for file %s: %s", s.st_size, name, strerror(errno)); + goto out; + } + br = read(fd, buf, s.st_size); + if (br != (ssize_t)s.st_size) { + Log(LOG_ERR, "Could not read file %s: read returned %ld, expected %ld: %s", + name, (long) br, (long) s.st_size, br == -1 ? strerror(errno):"short read?!"); + memset(buf, 0, s.st_size); + free(buf); + buf = NULL; + } else { + *len = br; + } +out: + close(fd); + return buf; +} +#endif + + +#ifdef HAVE_LIBSSL +static void +LogOpenSSLError( const char *msg, const char *msg2 ) +{ + unsigned long err = ERR_get_error(); + char * errmsg = err ? ERR_error_string(err, NULL) : "Unable to determine error"; + + if (!msg) msg = "SSL Error"; + if (msg2) + Log( LOG_ERR, "%s: %s: %s", msg, msg2, errmsg); + else + Log( LOG_ERR, "%s: %s", msg, errmsg); +} + + +static int +pem_passwd_cb(char *buf, int size, int rwflag, void *password) +{ + array *pass = password; + int passlen; + assert(rwflag == 0); /* 0 -> callback used for decryption. See SSL_CTX_set_default_passwd_cb(3) */ + + passlen = (int) array_bytes(pass); + + LogDebug("pem_passwd_cb buf size %d, array size %d", size, passlen); + assert(passlen >= 0); + if (passlen <= 0) { + Log(LOG_ERR, "pem_passwd_cb: password required, but not set"); + return 0; + } + size = passlen > size ? size : passlen; + memcpy(buf, (char *)(array_start(pass)), size); + return size; +} +#endif + + +static bool +Load_DH_params(void) +{ +#ifdef HAVE_LIBSSL + FILE *fp; + bool ret = true; + + if (!Conf_SSLOptions.DHFile) { + Log(LOG_NOTICE, "Configuration option \"SSLDHFile\" not set"); + return false; + } + fp = fopen(Conf_SSLOptions.DHFile, "r"); + if (!fp) { + Log(LOG_ERR, "%s: %s", Conf_SSLOptions.DHFile, strerror(errno)); + return false; + } + dh_params = PEM_read_DHparams(fp, NULL, NULL, NULL); + if (!dh_params) { + Log(LOG_ERR, "%s: PEM_read_DHparams failed", Conf_SSLOptions.DHFile); + ret = false; + } + fclose(fp); + return ret; +#endif +#ifdef HAVE_LIBGNUTLS + bool need_dhgenerate = true; + int err; + gnutls_dh_params_t tmp_dh_params; + + err = gnutls_dh_params_init(&tmp_dh_params); + if (err < 0) { + Log(LOG_ERR, "gnutls_dh_params_init: %s", gnutls_strerror(err)); + return false; + } + if (Conf_SSLOptions.DHFile) { + gnutls_datum_t dhparms; + size_t size; + dhparms.data = (unsigned char *) openreadclose(Conf_SSLOptions.DHFile, &size); + if (dhparms.data) { + dhparms.size = size; + err = gnutls_dh_params_import_pkcs3(tmp_dh_params, &dhparms, GNUTLS_X509_FMT_PEM); + if (err == 0) + need_dhgenerate = false; + else + Log(LOG_ERR, "gnutls_dh_params_init: %s", gnutls_strerror(err)); + + memset(dhparms.data, 0, size); + free(dhparms.data); + } + } + if (need_dhgenerate) { + Log(LOG_WARNING, "SSLDHFile not set, generating %u bit DH parameters. This may take a while...", DH_BITS); + err = gnutls_dh_params_generate2(tmp_dh_params, DH_BITS); + if (err < 0) { + Log(LOG_ERR, "gnutls_dh_params_generate2: %s", gnutls_strerror(err)); + return false; + } + } + dh_params = tmp_dh_params; + return true; +#endif +} + + +void ConnSSL_Free(CONNECTION *c) +{ +#ifdef HAVE_LIBSSL + SSL *ssl = c->ssl_state.ssl; + if (ssl) { + SSL_shutdown(ssl); + SSL_free(ssl); + c->ssl_state.ssl = NULL; + } +#endif +#ifdef HAVE_LIBGNUTLS + gnutls_session_t sess = c->ssl_state.gnutls_session; + if (Conn_OPTION_ISSET(c, CONN_SSL)) { + gnutls_bye(sess, GNUTLS_SHUT_RDWR); + gnutls_deinit(sess); + } +#endif + assert(Conn_OPTION_ISSET(c, CONN_SSL)); + Conn_OPTION_DEL(c, (CONN_SSL_CONNECT|CONN_SSL|CONN_SSL_WANT_WRITE)); +} + + +bool +ConnSSL_InitLibrary( void ) +{ +#ifdef HAVE_LIBSSL + SSL_CTX *newctx; + + if (!ssl_ctx) { + SSL_library_init(); + SSL_load_error_strings(); + } + + if (!RAND_status()) { + Log(LOG_ERR, "OpenSSL PRNG not seeded: /dev/urandom missing?"); + /* + * it is probably best to fail and let the user install EGD or a similar program if no kernel random device is available. + * According to OpenSSL RAND_egd(3): "The automatic query of /var/run/egd-pool et al was added in OpenSSL 0.9.7"; + * so it makes little sense to deal with PRNGD seeding ourselves. + */ + return false; + } + + newctx = SSL_CTX_new(SSLv23_method()); + if (!newctx) { + LogOpenSSLError("SSL_CTX_new()", NULL); + return false; + } + + if (!ConnSSL_LoadServerKey_openssl(newctx)) + goto out; + + SSL_CTX_set_options(newctx, SSL_OP_SINGLE_DH_USE|SSL_OP_NO_SSLv2); + SSL_CTX_set_mode(newctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_free(ssl_ctx); + ssl_ctx = newctx; + Log(LOG_INFO, "%s initialized", SSLeay_version(SSLEAY_VERSION)); + return true; +out: + SSL_CTX_free(newctx); + return false; +#endif +#ifdef HAVE_LIBGNUTLS + int err; + static bool initialized; + if (initialized) /* TODO: cannot reload gnutls keys: can't simply free x509 context -- it may still be in use */ + return false; + + err = gnutls_global_init(); + if (err) { + Log(LOG_ERR, "gnutls_global_init(): %s", gnutls_strerror(err)); + return false; + } + if (!ConnSSL_LoadServerKey_gnutls()) + return false; + Log(LOG_INFO, "gnutls %s initialized", gnutls_check_version(NULL)); + initialized = true; + return true; +#endif +} + + +#ifdef HAVE_LIBGNUTLS +static bool +ConnSSL_LoadServerKey_gnutls(void) +{ + int err; + const char *cert_file; + + err = gnutls_certificate_allocate_credentials(&x509_cred); + if (err < 0) { + Log(LOG_ERR, "gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err)); + return false; + } + + cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile; + if (!cert_file) { + Log(LOG_ERR, "Neither Key nor certificate File set"); + return false; + } + + if (array_bytes(&Conf_SSLOptions.KeyFilePassword)) + Log(LOG_WARNING, "Ignoring KeyFilePassword: Not supported by GNUTLS"); + + if (!Load_DH_params()) + return false; + + gnutls_certificate_set_dh_params(x509_cred, dh_params); + err = gnutls_certificate_set_x509_key_file(x509_cred, cert_file, Conf_SSLOptions.KeyFile, GNUTLS_X509_FMT_PEM); + if (err < 0) { + Log(LOG_ERR, "gnutls_certificate_set_x509_key_file (cert %s, key %s): %s", + cert_file, Conf_SSLOptions.KeyFile ? Conf_SSLOptions.KeyFile : "(NULL)", gnutls_strerror(err)); + return false; + } + return true; +} +#endif + + +#ifdef HAVE_LIBSSL +static bool +ConnSSL_LoadServerKey_openssl(SSL_CTX *ctx) +{ + char *cert_key; + + assert(ctx); + if (!Conf_SSLOptions.KeyFile) { + Log(LOG_NOTICE, "No SSL Server Key configured, ssl disabled"); + return false; + } + + SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb); + SSL_CTX_set_default_passwd_cb_userdata(ctx, &Conf_SSLOptions.KeyFilePassword); + + if (SSL_CTX_use_PrivateKey_file(ctx, Conf_SSLOptions.KeyFile, SSL_FILETYPE_PEM) != 1) { + array_free_wipe(&Conf_SSLOptions.KeyFilePassword); + LogOpenSSLError("SSL_CTX_use_PrivateKey_file", Conf_SSLOptions.KeyFile); + return false; + } + + cert_key = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile; + if (SSL_CTX_use_certificate_chain_file(ctx, cert_key) != 1) { + array_free_wipe(&Conf_SSLOptions.KeyFilePassword); + LogOpenSSLError("SSL_CTX_use_certificate_file", cert_key); + return false; + } + + array_free_wipe(&Conf_SSLOptions.KeyFilePassword); + + if (!SSL_CTX_check_private_key(ctx)) { + LogOpenSSLError("Server Private Key does not match certificate", NULL); + return false; + } + if (Load_DH_params()) { + if (SSL_CTX_set_tmp_dh(ctx, dh_params) != 1) + LogOpenSSLError("Error setting DH Parameters", Conf_SSLOptions.DHFile); + /* don't return false here: the non-DH modes will still work */ + DH_free(dh_params); + dh_params = NULL; + } + return true; +} + + +#endif +static bool +ConnSSL_Init_SSL(CONNECTION *c) +{ + int ret; + assert(c != NULL); +#ifdef HAVE_LIBSSL + assert(ssl_ctx); + if (!ssl_ctx) /* NULL when library initialization failed */ + return false; + + assert(c->ssl_state.ssl == NULL); + + c->ssl_state.ssl = SSL_new(ssl_ctx); + if (!c->ssl_state.ssl) { + LogOpenSSLError("SSL_new()", NULL); + return false; + } + + ret = SSL_set_fd(c->ssl_state.ssl, c->sock); + if (ret != 1) { + LogOpenSSLError("SSL_set_fd()", NULL); + ConnSSL_Free(c); + return false; + } +#endif +#ifdef HAVE_LIBGNUTLS + ret = gnutls_set_default_priority(c->ssl_state.gnutls_session); + if (ret < 0) { + Log(LOG_ERR, "gnutls_set_default_priority: %s", gnutls_strerror(ret)); + ConnSSL_Free(c); + } + gnutls_transport_set_ptr(c->ssl_state.gnutls_session, (gnutls_transport_ptr_t) c->sock); + ret = gnutls_credentials_set(c->ssl_state.gnutls_session, GNUTLS_CRD_CERTIFICATE, x509_cred); + if (ret < 0) { + Log(LOG_ERR, "gnutls_credentials_set: %s", gnutls_strerror(ret)); + ConnSSL_Free(c); + } + gnutls_dh_set_prime_bits(c->ssl_state.gnutls_session, DH_BITS); +#endif + Conn_OPTION_ADD(c, CONN_SSL); + return true; +} + + +bool +ConnSSL_PrepareConnect(CONNECTION *c, UNUSED CONF_SERVER *s) +{ + bool ret; +#ifdef HAVE_LIBGNUTLS + int err; +#endif + assert(c != NULL); + assert(s != NULL); +#ifdef HAVE_LIBGNUTLS + err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_CLIENT); + if (err) { + Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err)); + return false; + } +#endif + ret = ConnSSL_Init_SSL(c); + if (!ret) + return false; + Conn_OPTION_ADD(c, CONN_SSL_CONNECT); +#ifdef HAVE_LIBSSL + assert(c->ssl_state.ssl); + SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_NONE, NULL); +#endif + return true; +} + + +/* + Check an Handle Error return code after failed calls to ssl/tls functions. + OpenSSL: + SSL_connect(), SSL_accept(), SSL_do_handshake(), SSL_read(), SSL_peek(), or SSL_write() on ssl. + GNUTLS: + gnutlsssl_read(), gnutls_write() or gnutls_handshake(). + Return: -1 on fatal error, 0 if we can try again later. + */ +static int +ConnSSL_HandleError( CONNECTION *c, const int code, const char *fname ) +{ +#ifdef HAVE_LIBSSL + int ret = SSL_ERROR_SYSCALL; + unsigned long sslerr; + int real_errno = errno; + + assert( fname ); + + ret = SSL_get_error(c->ssl_state.ssl, code); + switch (ret) { + case SSL_ERROR_WANT_READ: + io_event_del(c->sock, IO_WANTWRITE); + Conn_OPTION_ADD(c, CONN_SSL_WANT_READ); + return 0; /* try again later */ + case SSL_ERROR_WANT_WRITE: + io_event_del(c->sock, IO_WANTREAD); + Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */ + case SSL_ERROR_NONE: + return 0; /* try again later */ + case SSL_ERROR_ZERO_RETURN: /* TLS/SSL Connection was shut down */ + LogOpenSSLError("TLS/SSL Connection shutdown", fname); + break; + /* + SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT, SSL_ERROR_WANT_X509_LOOKUP + */ + case SSL_ERROR_SYSCALL: + sslerr = ERR_get_error(); + if (sslerr) { + Log( LOG_ERR, "%s: %s", fname, ERR_error_string(sslerr, NULL )); + } else { + + switch (code) { /* EOF that violated protocol */ + case 0: + Log(LOG_ERR, "%s: Client Disconnected", fname ); + break; + case -1: /* low level socket I/O error, check errno */ + Log(LOG_ERR, "%s: %s", fname, strerror(real_errno)); + } + } + break; + case SSL_ERROR_SSL: + LogOpenSSLError("TLS/SSL Protocol Error", fname); + break; + default: + Log( LOG_ERR, "%s: Unknown error %d!", fname, ret); + } + ConnSSL_Free(c); + return -1; +#endif +#ifdef HAVE_LIBGNUTLS + switch (code) { + case GNUTLS_E_AGAIN: + case GNUTLS_E_INTERRUPTED: + if (gnutls_record_get_direction(c->ssl_state.gnutls_session)) { /* need write */ + io_event_del(c->sock, IO_WANTREAD); + Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */ + break; + } else { /* need read */ + io_event_del(c->sock, IO_WANTWRITE); + Conn_OPTION_ADD(c, CONN_SSL_WANT_READ); + break; + } + default: + assert(code < 0); + if (gnutls_error_is_fatal(code)) { + Log(LOG_ERR, "%s: %s", fname, gnutls_strerror(code)); + ConnSSL_Free(c); + return -1; + } + } + return 0; +#endif +} + + +static void +ConnSSL_LogCertInfo( CONNECTION *c ) +{ +#ifdef HAVE_LIBSSL + SSL *ssl = c->ssl_state.ssl; + + assert( c ); + assert( ssl ); + + Log( LOG_INFO, "New %s connection using cipher %s on socket %d", + SSL_get_version(ssl), SSL_get_cipher(ssl), c->sock); +#endif +#ifdef HAVE_LIBGNUTLS + gnutls_credentials_type_t cred; + gnutls_session_t sess = c->ssl_state.gnutls_session; + gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess); + + Log( LOG_INFO, "New %s connection using cipher %s-%s on socket %d", + gnutls_protocol_get_name(gnutls_protocol_get_version(sess)), + gnutls_cipher_get_name(cipher), gnutls_mac_get_name(gnutls_mac_get(sess)), c->sock); +#endif +} + + +/* + Accept incoming SSL connection. + Return Values: + 1: SSL Connection established + 0: try again + -1: SSL Connection not established due to fatal error. +*/ +int +ConnSSL_Accept( CONNECTION *c ) +{ + assert(c != NULL); +#ifdef HAVE_LIBSSL + if (!c->ssl_state.ssl) { +#endif +#ifdef HAVE_LIBGNUTLS + if (!Conn_OPTION_ISSET(c, CONN_SSL)) { + int err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_SERVER); + if (err) { + Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err)); + return false; + } +#endif + LogDebug("ConnSSL_Accept: Initializing SSL data"); + if (!ConnSSL_Init_SSL(c)) + return -1; + } + return ConnectAccept(c, false ); +} + + +int +ConnSSL_Connect( CONNECTION *c ) +{ + assert(c != NULL); +#ifdef HAVE_LIBSSL + assert(c->ssl_state.ssl); +#endif +#ifdef HAVE_LIBGNUTLS + assert(Conn_OPTION_ISSET(c, CONN_SSL)); +#endif + return ConnectAccept(c, true); +} + + +/* accept/connect wrapper. if connect is true, connect to peer, otherwise wait for incoming connection */ +static int +ConnectAccept( CONNECTION *c, bool connect) +{ + int ret; +#ifdef HAVE_LIBSSL + SSL *ssl = c->ssl_state.ssl; + assert(ssl != NULL); + + ret = connect ? SSL_connect(ssl) : SSL_accept(ssl); + if (1 != ret) + return ConnSSL_HandleError(c, ret, connect ? "SSL_connect": "SSL_accept"); +#endif +#ifdef HAVE_LIBGNUTLS + (void) connect; + assert(Conn_OPTION_ISSET(c, CONN_SSL)); + ret = gnutls_handshake(c->ssl_state.gnutls_session); + if (ret) + return ConnSSL_HandleError(c, ret, "gnutls_handshake"); +#endif /* _GNUTLS */ + Conn_OPTION_DEL(c, (CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ|CONN_SSL_CONNECT)); + ConnSSL_LogCertInfo(c); + return 1; +} + + +ssize_t +ConnSSL_Write(CONNECTION *c, const void *buf, size_t count) +{ + ssize_t bw; + + Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ); + + assert(count > 0); +#ifdef HAVE_LIBSSL + bw = (ssize_t) SSL_write(c->ssl_state.ssl, buf, count); +#endif +#ifdef HAVE_LIBGNUTLS + bw = gnutls_write(c->ssl_state.gnutls_session, buf, count); +#endif + if ( bw > 0 ) return bw; + if (ConnSSL_HandleError( c, bw, "ConnSSL_Write") == 0) + errno = EAGAIN; /* try again */ + return -1; +} + + +ssize_t +ConnSSL_Read(CONNECTION *c, void * buf, size_t count) +{ + ssize_t br; + + Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ); +#ifdef HAVE_LIBSSL + br = (ssize_t) SSL_read(c->ssl_state.ssl, buf, count); + if (br > 0) /* on EOF we have to call ConnSSL_HandleError(), see SSL_read(3) */ + return br; +#endif +#ifdef HAVE_LIBGNUTLS + br = gnutls_read(c->ssl_state.gnutls_session, buf, count); + if (br >= 0) /* on EOF we must _not_ call ConnSSL_HandleError, see gnutls_record_recv(3) */ + return br; +#endif + /* error on read: switch ConnSSL_HandleError() return values -> 0 is "try again", so return -1 and set EAGAIN */ + if (ConnSSL_HandleError(c, br, "ConnSSL_Read") == 0) { + errno = EAGAIN; + return -1; + } + return 0; +} + + +bool +ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len) +{ +#ifdef HAVE_LIBSSL + SSL *ssl; + assert(c != NULL); + assert(len >= 128); + ssl = c->ssl_state.ssl; + if (!ssl) return false; + return SSL_CIPHER_description(SSL_get_current_cipher(ssl), buf, len) != NULL; +#endif +#ifdef HAVE_LIBGNUTLS + assert(c != NULL); + assert(len >= 128); + if (Conn_OPTION_ISSET(c, CONN_SSL)) { + const char *name_cipher, *name_mac, *name_proto, *name_keyexchange; + unsigned keysize; + + gnutls_session_t sess = c->ssl_state.gnutls_session; + gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess); + name_cipher = gnutls_cipher_get_name(cipher); + name_mac = gnutls_mac_get_name(gnutls_mac_get(sess)); + keysize = gnutls_cipher_get_key_size(cipher) * 8; + name_proto = gnutls_protocol_get_name(gnutls_protocol_get_version(sess)); + name_keyexchange = gnutls_kx_get_name(gnutls_kx_get(sess)); + + return snprintf(buf, len, "%s-%s%15s Kx=%s Enc=%s(%u) Mac=%s\n", + name_cipher, name_mac, name_proto, name_keyexchange, name_cipher, keysize, name_mac) > 0; + } + return false; +#endif +} + + +#endif /* SSL_SUPPORT */ +/* -eof- */ + + diff --git a/src/ngircd/conn-ssl.h b/src/ngircd/conn-ssl.h new file mode 100644 index 00000000..4cb1bde0 --- /dev/null +++ b/src/ngircd/conn-ssl.h @@ -0,0 +1,28 @@ +/* + * ngIRCd -- The Next Generation IRC Daemon + * SSL wrapper functions. (header) + */ + +#ifndef conn_ssl_h +#define conn_ssl_h + +#include "conf-ssl.h" +#include "conn.h" +#include "conf.h" + +#ifdef SSL_SUPPORT +GLOBAL void ConnSSL_Free PARAMS(( CONNECTION *c )); + +GLOBAL bool ConnSSL_PrepareConnect PARAMS(( CONNECTION *c, CONF_SERVER *s )); + +GLOBAL int ConnSSL_Accept PARAMS(( CONNECTION *c )); +GLOBAL int ConnSSL_Connect PARAMS(( CONNECTION *c )); + +GLOBAL ssize_t ConnSSL_Write PARAMS(( CONNECTION *c, const void *buf, size_t count)); +GLOBAL ssize_t ConnSSL_Read PARAMS(( CONNECTION *c, void *buf, size_t count)); + +GLOBAL bool ConnSSL_GetCipherInfo PARAMS(( CONNECTION *c, char *buf, size_t len )); +#endif /* SSL_SUPPORT */ +#endif /* conn_ssl_h */ + +/* -eof- */ -- 2.39.2