X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fconn-ssl.c;h=914d01651235ad16af2e81ebb3d9a045e1d39a37;hp=8995adbe4f4e8f8344597833c1d6e7627b4d76dc;hb=8cfb9104419d3c00fbef3fe8639eb04f03d83f3d;hpb=2fce881d969402642cffff1ee336a37dd404b212 diff --git a/src/ngircd/conn-ssl.c b/src/ngircd/conn-ssl.c index 8995adbe..914d0165 100644 --- a/src/ngircd/conn-ssl.c +++ b/src/ngircd/conn-ssl.c @@ -1,11 +1,15 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * - * SSL wrapper functions. * Copyright (c) 2005-2008 Florian Westphal */ #include "portab.h" + +/** + * @file + * SSL wrapper functions + */ + #include "imp.h" #include "conf-ssl.h" @@ -47,10 +51,11 @@ static bool ConnSSL_LoadServerKey_openssl PARAMS(( SSL_CTX *c )); #include #include -#define DH_BITS 1024 +#define DH_BITS 2048 +#define DH_BITS_MIN 1024 + static gnutls_certificate_credentials_t x509_cred; static gnutls_dh_params_t dh_params; - static bool ConnSSL_LoadServerKey_gnutls PARAMS(( void )); #endif @@ -123,7 +128,10 @@ 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) */ + + (void)rwflag; /* rwflag is unused if DEBUG is not set. */ + assert(rwflag == 0); /* 0 -> callback used for decryption. + * See SSL_CTX_set_default_passwd_cb(3) */ passlen = (int) array_bytes(pass); @@ -148,7 +156,7 @@ Load_DH_params(void) bool ret = true; if (!Conf_SSLOptions.DHFile) { - Log(LOG_NOTICE, "Configuration option \"SSLDHFile\" not set"); + Log(LOG_NOTICE, "Configuration option \"SSLDHFile\" not set!"); return false; } fp = fopen(Conf_SSLOptions.DHFile, "r"); @@ -158,7 +166,8 @@ Load_DH_params(void) } dh_params = PEM_read_DHparams(fp, NULL, NULL, NULL); if (!dh_params) { - Log(LOG_ERR, "%s: PEM_read_DHparams failed", Conf_SSLOptions.DHFile); + Log(LOG_ERR, "%s: PEM_read_DHparams failed!", + Conf_SSLOptions.DHFile); ret = false; } fclose(fp); @@ -191,7 +200,9 @@ Load_DH_params(void) } } if (need_dhgenerate) { - Log(LOG_WARNING, "SSLDHFile not set, generating %u bit DH parameters. This may take a while...", DH_BITS); + 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)); @@ -222,13 +233,17 @@ void ConnSSL_Free(CONNECTION *c) } #endif assert(Conn_OPTION_ISSET(c, CONN_SSL)); - Conn_OPTION_DEL(c, (CONN_SSL_CONNECT|CONN_SSL|CONN_SSL_WANT_WRITE)); + /* can't just set bitmask to 0 -- there are other, non-ssl related flags, e.g. CONN_ZIP. */ + Conn_OPTION_DEL(c, CONN_SSL_FLAGS_ALL); } bool ConnSSL_InitLibrary( void ) { + if (!array_bytes(&Conf_SSLOptions.ListenPorts)) + return true; + #ifdef HAVE_LIBSSL SSL_CTX *newctx; @@ -244,12 +259,14 @@ ConnSSL_InitLibrary( void ) * 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. */ + array_free(&Conf_SSLOptions.ListenPorts); return false; } newctx = SSL_CTX_new(SSLv23_method()); if (!newctx) { LogOpenSSLError("SSL_CTX_new()", NULL); + array_free(&Conf_SSLOptions.ListenPorts); return false; } @@ -260,10 +277,11 @@ ConnSSL_InitLibrary( void ) 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)); + Log(LOG_INFO, "%s initialized.", SSLeay_version(SSLEAY_VERSION)); return true; out: SSL_CTX_free(newctx); + array_free(&Conf_SSLOptions.ListenPorts); return false; #endif #ifdef HAVE_LIBGNUTLS @@ -275,11 +293,14 @@ out: err = gnutls_global_init(); if (err) { Log(LOG_ERR, "gnutls_global_init(): %s", gnutls_strerror(err)); + array_free(&Conf_SSLOptions.ListenPorts); return false; } - if (!ConnSSL_LoadServerKey_gnutls()) + if (!ConnSSL_LoadServerKey_gnutls()) { + array_free(&Conf_SSLOptions.ListenPorts); return false; - Log(LOG_INFO, "gnutls %s initialized", gnutls_check_version(NULL)); + } + Log(LOG_INFO, "gnutls %s initialized.", gnutls_check_version(NULL)); initialized = true; return true; #endif @@ -301,12 +322,13 @@ ConnSSL_LoadServerKey_gnutls(void) cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile; if (!cert_file) { - Log(LOG_ERR, "Neither Key nor certificate File set"); + Log(LOG_ERR, "No SSL server key configured!"); return false; } if (array_bytes(&Conf_SSLOptions.KeyFilePassword)) - Log(LOG_WARNING, "Ignoring KeyFilePassword: Not supported by GNUTLS"); + Log(LOG_WARNING, + "Ignoring KeyFilePassword: Not supported by GNUTLS."); if (!Load_DH_params()) return false; @@ -331,7 +353,7 @@ ConnSSL_LoadServerKey_openssl(SSL_CTX *ctx) assert(ctx); if (!Conf_SSLOptions.KeyFile) { - Log(LOG_NOTICE, "No SSL Server Key configured, ssl disabled"); + Log(LOG_ERR, "No SSL server key configured!"); return false; } @@ -375,10 +397,10 @@ ConnSSL_Init_SSL(CONNECTION *c) int ret; assert(c != NULL); #ifdef HAVE_LIBSSL - assert(ssl_ctx); - if (!ssl_ctx) /* NULL when library initialization failed */ + if (!ssl_ctx) { + Log(LOG_ERR, "Cannot init ssl_ctx: OpenSSL initialization failed at startup"); return false; - + } assert(c->ssl_state.ssl == NULL); c->ssl_state.ssl = SSL_new(ssl_ctx); @@ -399,14 +421,22 @@ ConnSSL_Init_SSL(CONNECTION *c) if (ret < 0) { Log(LOG_ERR, "gnutls_set_default_priority: %s", gnutls_strerror(ret)); ConnSSL_Free(c); + return false; } - gnutls_transport_set_ptr(c->ssl_state.gnutls_session, (gnutls_transport_ptr_t) c->sock); + /* + * The intermediate (long) cast is here to avoid a warning like: + * "cast to pointer from integer of different size" on 64-bit platforms. + * There doesn't seem to be an alternate GNUTLS API we could use instead, see e.g. + * http://www.mail-archive.com/help-gnutls@gnu.org/msg00286.html + */ + gnutls_transport_set_ptr(c->ssl_state.gnutls_session, (gnutls_transport_ptr_t) (long) 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); + return false; } - gnutls_dh_set_prime_bits(c->ssl_state.gnutls_session, DH_BITS); + gnutls_dh_set_prime_bits(c->ssl_state.gnutls_session, DH_BITS_MIN); #endif Conn_OPTION_ADD(c, CONN_SSL); return true; @@ -419,10 +449,7 @@ 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)); @@ -457,8 +484,6 @@ ConnSSL_HandleError( CONNECTION *c, const int code, const char *fname ) 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: @@ -470,8 +495,8 @@ ConnSSL_HandleError( CONNECTION *c, const int code, const char *fname ) 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); + case SSL_ERROR_ZERO_RETURN: + LogDebug("TLS/SSL connection shut down normally"); break; /* SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT, SSL_ERROR_WANT_X509_LOOKUP @@ -504,15 +529,14 @@ ConnSSL_HandleError( CONNECTION *c, const int code, const char *fname ) 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); + if (gnutls_record_get_direction(c->ssl_state.gnutls_session)) { + Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); + io_event_del(c->sock, IO_WANTREAD); + } else { + Conn_OPTION_ADD(c, CONN_SSL_WANT_READ); + io_event_del(c->sock, IO_WANTWRITE); + } break; - } default: assert(code < 0); if (gnutls_error_is_fatal(code)) { @@ -532,20 +556,20 @@ ConnSSL_LogCertInfo( CONNECTION *c ) #ifdef HAVE_LIBSSL SSL *ssl = c->ssl_state.ssl; - assert( c ); - assert( ssl ); + assert(ssl); - Log( LOG_INFO, "New %s connection using cipher %s on socket %d", - SSL_get_version(ssl), SSL_get_cipher(ssl), c->sock); + Log(LOG_INFO, "Connection %d: initialized %s using cipher %s.", + c->sock, SSL_get_version(ssl), SSL_get_cipher(ssl)); #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); + Log(LOG_INFO, "Connection %d: initialized %s using cipher %s-%s.", + c->sock, + gnutls_protocol_get_name(gnutls_protocol_get_version(sess)), + gnutls_cipher_get_name(cipher), + gnutls_mac_get_name(gnutls_mac_get(sess))); #endif } @@ -561,11 +585,8 @@ 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)) { +#ifdef HAVE_LIBGNUTLS int err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_SERVER); if (err) { Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err)); @@ -587,9 +608,7 @@ ConnSSL_Connect( CONNECTION *c ) #ifdef HAVE_LIBSSL assert(c->ssl_state.ssl); #endif -#ifdef HAVE_LIBGNUTLS assert(Conn_OPTION_ISSET(c, CONN_SSL)); -#endif return ConnectAccept(c, true); } @@ -609,13 +628,14 @@ ConnectAccept( CONNECTION *c, bool connect) #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); + + Conn_StartLogin(CONNECTION2ID(c)); return 1; } @@ -634,7 +654,8 @@ ConnSSL_Write(CONNECTION *c, const void *buf, size_t count) #ifdef HAVE_LIBGNUTLS bw = gnutls_write(c->ssl_state.gnutls_session, buf, count); #endif - if ( bw > 0 ) return bw; + if (bw > 0) + return bw; if (ConnSSL_HandleError( c, bw, "ConnSSL_Write") == 0) errno = EAGAIN; /* try again */ return -1; @@ -671,11 +692,8 @@ ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len) { #ifdef HAVE_LIBSSL char *nl; + SSL *ssl = c->ssl_state.ssl; - SSL *ssl; - assert(c != NULL); - assert(len >= 128); - ssl = c->ssl_state.ssl; if (!ssl) return false; *buf = 0; @@ -686,8 +704,6 @@ ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len) return true; #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;