diff --git a/Makefile.am b/Makefile.am index 719f73d..8844519 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ src_bip_SOURCES = src/conf.y src/lex.l \ src/line.c src/line.h \ src/log.c src/log.h \ src/md5.c src/md5.h \ - src/moduli.h \ + src/path_util.c src/path_util.h \ src/tuple.h \ src/util.c src/util.h src_bipmkpw_SOURCES = src/bipmkpw.c src/md5.c src/util.c diff --git a/bip.conf.5 b/bip.conf.5 index 2dedcc5..9ca0ef8 100644 --- a/bip.conf.5 +++ b/bip.conf.5 @@ -1,4 +1,4 @@ -.TH BIP.CONF 5 "10 October 2005" +.TH BIP.CONF 5 "04 July 2016" .SH NAME @@ -82,6 +82,10 @@ SSL connections. \fBclient_side_ciphers\fP OpenSSL cipher lists used for clients SSL connections. +.TP +\fBclient_side_dh_param\fP DH parameters filename\fP (default: \fB/dh.pem\fP) +Used for clients SSL connections, Supply at least 2048-bit parameters. + .TP \fBssl_default_ciphers\fP OpenSSL cipher lists used for server connections. diff --git a/samples/bip.conf b/samples/bip.conf index 7ea38a6..3f37a92 100644 --- a/samples/bip.conf +++ b/samples/bip.conf @@ -23,6 +23,11 @@ client_side_ssl = false; # OpenSSL cipher lists used with SSL client connections. #client_side_ciphers = "ECDHE-RSA-AES128-GCM-SHA256"; +# DH parameters bip'll use when serving SSL clients. +# Supply at least 2048-bit parameters, for example using openssl: +# openssl dhparam -out dh.pem 2048; +#client_side_dh_param = "dh.pem"; + # Default OpenSSL cipher lists used with outgoing connections to IRC servers. #ssl_default_ciphers = "ECDHE-RSA-AES128-GCM-SHA256"; diff --git a/samples/bip.vim b/samples/bip.vim index 5a7ef90..9f91f20 100644 --- a/samples/bip.vim +++ b/samples/bip.vim @@ -56,7 +56,7 @@ syn keyword bipKeyword contained nextgroup=bipBoolV client_side_ssl \ log log_system syn keyword bipKeyword contained nextgroup=bipStringV log_root \ log_format oidentd_file pid_file client_side_ssl_pem client_side_ciphers - \ ssl_default_ciphers + \ client_side_dh_param ssl_default_ciphers syn keyword bipKeyword contained nextgroup=bipNumericV port log_level \ log_sync_interval syn keyword bipKeyword contained nextgroup=bipIPV ip diff --git a/src/bip.c b/src/bip.c index 54a11ae..e10d009 100644 --- a/src/bip.c +++ b/src/bip.c @@ -25,6 +25,7 @@ #include #include "irc.h" #include "conf.h" +#include "path_util.h" #include "tuple.h" #include "log.h" #include "bip.h" @@ -42,6 +43,7 @@ int conf_css; #ifdef HAVE_LIBSSL char *conf_ssl_certfile; char *conf_client_ciphers; +char *conf_client_dh_file; char *conf_server_default_ciphers; #endif int conf_daemonize; @@ -1019,11 +1021,15 @@ int fireup(bip_t *bip, FILE *conf) case LEX_CSS_PEM: MOVE_STRING(conf_ssl_certfile, t->pdata); break; + case LEX_DH_PARAM: + MOVE_STRING(conf_client_dh_file, t->pdata); + break; #else case LEX_DEFAULT_CIPHERS: case LEX_CSS: case LEX_CSS_CIPHERS: case LEX_CSS_PEM: + case LEX_DH_PARAM: mylog(LOG_WARN, "Found SSL option whereas bip is " "not built with SSL support."); break; @@ -1223,6 +1229,7 @@ int main(int argc, char **argv) conf_ssl_certfile = NULL; conf_client_ciphers = NULL; conf_server_default_ciphers = NULL; + conf_client_dh_file = NULL; #endif while ((ch = getopt(argc, argv, "hvnf:s:")) != -1) { @@ -1309,24 +1316,14 @@ int main(int argc, char **argv) #ifdef HAVE_LIBSSL if (conf_css) { - int e, fd; + int e; struct stat fs; if (!conf_ssl_certfile) { - char *ap = "/bip.pem"; - conf_ssl_certfile = bip_malloc(strlen(conf_biphome) + - strlen(ap) + 1); - strcpy(conf_ssl_certfile, conf_biphome); - strcat(conf_ssl_certfile, ap); - mylog(LOG_INFO, "Using default SSL certificate file: " - "%s", conf_ssl_certfile); + conf_ssl_certfile = default_path(conf_biphome, "bip.pem", + "SSL certificate"); } - - if ((fd = open(conf_ssl_certfile, O_RDONLY)) == -1) - fatal("Unable to open PEM file %s for reading", - conf_ssl_certfile); - else - close(fd); + assert_path_exists(conf_ssl_certfile); e = stat(conf_ssl_certfile, &fs); if (e) @@ -1336,6 +1333,12 @@ int main(int argc, char **argv) mylog(LOG_ERROR, "PEM file %s should not be world " "readable / writable. Please fix the modes.", conf_ssl_certfile); + + if (!conf_client_dh_file) { + conf_client_dh_file = default_path(conf_biphome, "dh.pem", + "DH parameters"); + } + assert_path_exists(conf_client_dh_file); } #endif diff --git a/src/conf.y b/src/conf.y index fda894b..11cc50d 100644 --- a/src/conf.y +++ b/src/conf.y @@ -68,7 +68,7 @@ struct tuple *tuple_l_new(int type, void *p) %} -%token LEX_IP LEX_EQ LEX_PORT LEX_CSS LEX_SEMICOLON LEX_CONNECTION LEX_NETWORK LEX_LBRA LEX_RBRA LEX_USER LEX_NAME LEX_NICK LEX_SERVER LEX_PASSWORD LEX_SRCIP LEX_HOST LEX_VHOST LEX_SOURCE_PORT LEX_NONE LEX_COMMENT LEX_BUNCH LEX_REALNAME LEX_SSL LEX_SSL_CHECK_MODE LEX_SSL_CHECK_STORE LEX_SSL_CLIENT_CERTFILE LEX_CIPHERS LEX_CSS_CIPHERS LEX_DEFAULT_CIPHERS LEX_CHANNEL LEX_KEY LEX_LOG_ROOT LEX_LOG_FORMAT LEX_LOG_LEVEL LEX_BACKLOG_LINES LEX_BACKLOG_NO_TIMESTAMP LEX_BACKLOG LEX_LOG LEX_LOG_SYSTEM LEX_LOG_SYNC_INTERVAL LEX_FOLLOW_NICK LEX_ON_CONNECT_SEND LEX_AWAY_NICK LEX_PID_FILE LEX_OIDENTD_FILE LEX_IGN_FIRST_NICK LEX_ALWAYS_BACKLOG LEX_BLRESET_ON_TALK LEX_BLRESET_CONNECTION LEX_DEFAULT_USER LEX_DEFAULT_NICK LEX_DEFAULT_REALNAME LEX_NO_CLIENT_AWAY_MSG LEX_BL_MSG_ONLY LEX_ADMIN LEX_BIP_USE_NOTICE LEX_CSS_PEM LEX_AUTOJOIN_ON_KICK LEX_IGNORE_CAPAB LEX_RECONN_TIMER +%token LEX_IP LEX_EQ LEX_PORT LEX_CSS LEX_SEMICOLON LEX_CONNECTION LEX_NETWORK LEX_LBRA LEX_RBRA LEX_USER LEX_NAME LEX_NICK LEX_SERVER LEX_PASSWORD LEX_SRCIP LEX_HOST LEX_VHOST LEX_SOURCE_PORT LEX_NONE LEX_COMMENT LEX_BUNCH LEX_REALNAME LEX_SSL LEX_SSL_CHECK_MODE LEX_SSL_CHECK_STORE LEX_SSL_CLIENT_CERTFILE LEX_CIPHERS LEX_CSS_CIPHERS LEX_DEFAULT_CIPHERS LEX_DH_PARAM LEX_CHANNEL LEX_KEY LEX_LOG_ROOT LEX_LOG_FORMAT LEX_LOG_LEVEL LEX_BACKLOG_LINES LEX_BACKLOG_NO_TIMESTAMP LEX_BACKLOG LEX_LOG LEX_LOG_SYSTEM LEX_LOG_SYNC_INTERVAL LEX_FOLLOW_NICK LEX_ON_CONNECT_SEND LEX_AWAY_NICK LEX_PID_FILE LEX_OIDENTD_FILE LEX_IGN_FIRST_NICK LEX_ALWAYS_BACKLOG LEX_BLRESET_ON_TALK LEX_BLRESET_CONNECTION LEX_DEFAULT_USER LEX_DEFAULT_NICK LEX_DEFAULT_REALNAME LEX_NO_CLIENT_AWAY_MSG LEX_BL_MSG_ONLY LEX_ADMIN LEX_BIP_USE_NOTICE LEX_CSS_PEM LEX_AUTOJOIN_ON_KICK LEX_IGNORE_CAPAB LEX_RECONN_TIMER %union { int number; @@ -101,6 +101,7 @@ command: | LEX_CSS_PEM LEX_EQ LEX_STRING { $$ = tuple_s_new(LEX_CSS_PEM, $3); } | LEX_CSS_CIPHERS LEX_EQ LEX_STRING { $$ = tuple_s_new(LEX_CSS_CIPHERS, $3); } | LEX_DEFAULT_CIPHERS LEX_EQ LEX_STRING { $$ = tuple_s_new(LEX_DEFAULT_CIPHERS, $3); } + | LEX_DH_PARAM LEX_EQ LEX_STRING { $$ = tuple_s_new(LEX_DH_PARAM, $3); } | LEX_LOG LEX_EQ LEX_BOOL { $$ = tuple_i_new(LEX_LOG, $3); } | LEX_LOG_SYSTEM LEX_EQ LEX_BOOL { $$ = tuple_i_new(LEX_LOG_SYSTEM, $3); } | LEX_LOG_SYNC_INTERVAL LEX_EQ LEX_INT { $$ = tuple_i_new( diff --git a/src/connection.c b/src/connection.c index a5fbb3d..65f06e4 100644 --- a/src/connection.c +++ b/src/connection.c @@ -25,6 +25,7 @@ extern FILE *conf_global_log_file; static BIO *errbio = NULL; extern char *conf_ssl_certfile; extern char *conf_client_ciphers; +extern char *conf_client_dh_file; static int SSLize(connection_t *cn, int *nc); static SSL_CTX *SSL_init_context(char *ciphers); /* SSH like trust management */ @@ -1126,81 +1127,39 @@ static connection_t *connection_init(int anti_flood, int ssl, int timeout, } #ifdef HAVE_LIBSSL - -#include "moduli.h" - -/* from postfix tls impl */ -static DH *dh_512(void) +static int ctx_set_dh(SSL_CTX *ctx) { - DH *dh; - BIGNUM *p; - BIGNUM *g; - static DH *dh_512; + /* Return ephemeral DH parameters. */ + DH *dh = NULL; + FILE *f; + int ret; - if (dh_512 == NULL) { - if ((dh = DH_new()) == NULL) { - mylog(LOG_WARN, "SSL: cannot create DH parameter set"); - return (0); - } - - p = BN_bin2bn(dh512_p, sizeof(dh512_p), (BIGNUM *) 0); - g = BN_bin2bn(dh512_g, sizeof(dh512_g), (BIGNUM *) 0); - - if ((p == NULL) || (g == NULL)) { - mylog(LOG_WARN, "SSL: cannot load compiled-in DH " - "parameters"); - DH_free(dh); - return (0); - } else { - DH_set0_pqg(dh, p, NULL, g); - dh_512 = dh; - } + /* Should not fail: already checked in main function */ + if ((f = fopen(conf_client_dh_file, "r")) == NULL) { + mylog(LOG_ERROR, "Unable to open DH parameters (%s): %s", + conf_client_dh_file, strerror(errno)); + return 0; } - return dh_512; -} -/* tls_get_dh_1024 - get 1024-bit DH parameters, compiled-in or from file */ -static DH *dh_1024(void) -{ - DH *dh; - BIGNUM *p; - BIGNUM *g; - static DH *dh_1024; + dh = PEM_read_DHparams(f, NULL, NULL, NULL); + fclose(f); - if (dh_1024 == NULL) { - if ((dh = DH_new()) == NULL) { - mylog(LOG_WARN, "SSL: cannot create DH parameter set"); - return (0); - } - - p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), (BIGNUM *) 0); - g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), (BIGNUM *) 0); - - if ((p == NULL) || (g == NULL)) { - mylog(LOG_WARN, "SSL: cannot load compiled-in DH " - "parameters"); - DH_free(dh); - return (0); - } else { - DH_set0_pqg(dh, p, NULL, g); - dh_1024 = dh; - } + if (dh == NULL) { + mylog(LOG_ERROR, "Could not parse DH parameters from: %s", + conf_client_dh_file); + return 0; } - return (dh_1024); -} -/* ripped from postfix's tls_dh.c */ -static DH *tmp_dh_cb(UNUSED(SSL *ssl_unused), int export, int keylength) -{ - DH *ret; + ret = SSL_CTX_set_tmp_dh(ctx, dh); + DH_free(dh); - if (export && keylength == 512) { - mylog(LOG_WARN, "SSL: using 512 bits diffie hellman moduli"); - ret = dh_512(); - } else { - ret = dh_1024(); + if (ret != 1) { + mylog(LOG_ERROR, "Unable to set DH parameters: %s", + ERR_error_string(ERR_get_error(), NULL)); + return 0; } - return ret; + + return 1; } #endif @@ -1247,6 +1206,14 @@ connection_t *accept_new(connection_t *cn) connection_free(conn); return NULL; } + + if (!ctx_set_dh(sslctx)) { + mylog(LOG_ERROR, "SSL Unable to load DH " + "parameters"); + connection_free(conn); + return NULL; + } + if (!SSL_CTX_use_certificate_chain_file(sslctx, conf_ssl_certfile)) mylog(LOG_WARN, "SSL: Unable to load " @@ -1255,10 +1222,6 @@ connection_t *accept_new(connection_t *cn) conf_ssl_certfile, SSL_FILETYPE_PEM)) mylog(LOG_WARN, "SSL: Unable to load key file"); - - /* diffie hellman key generation need us to feed some - data that can be static ... */ - SSL_CTX_set_tmp_dh_callback(sslctx, tmp_dh_cb); } conn->ssl_h = SSL_new(sslctx); diff --git a/src/lex.l b/src/lex.l index b291a2f..1a3680a 100644 --- a/src/lex.l +++ b/src/lex.l @@ -112,6 +112,7 @@ list_t *parse_conf(FILE *file, int *err) "bip_use_notice" { return LEX_BIP_USE_NOTICE; } "client_side_ssl_pem" { return LEX_CSS_PEM; } "client_side_ciphers" { return LEX_CSS_CIPHERS; } +"client_side_dh_param" { return LEX_DH_PARAM; } "ignore_server_capab" { return LEX_IGNORE_CAPAB; } "reconn_timer" { return LEX_RECONN_TIMER; } \"[^"]*\" { diff --git a/src/moduli.h b/src/moduli.h deleted file mode 100644 index aba669c..0000000 --- a/src/moduli.h +++ /dev/null @@ -1,38 +0,0 @@ -/* ripped from postfix tls_dh.c */ - - /* - * Compiled-in DH parameters. These are used when no parameters are - * explicitly loaded from file. - * - * XXX What is the origin of these parameters? - */ -static unsigned char dh512_p[] = { - 0x88, 0x3F, 0x00, 0xAF, 0xFC, 0x0C, 0x8A, 0xB8, 0x35, 0xCD, 0xE5, 0xC2, - 0x0F, 0x55, 0xDF, 0x06, 0x3F, 0x16, 0x07, 0xBF, 0xCE, 0x13, 0x35, 0xE4, - 0x1C, 0x1E, 0x03, 0xF3, 0xAB, 0x17, 0xF6, 0x63, 0x50, 0x63, 0x67, 0x3E, - 0x10, 0xD7, 0x3E, 0xB4, 0xEB, 0x46, 0x8C, 0x40, 0x50, 0xE6, 0x91, 0xA5, - 0x6E, 0x01, 0x45, 0xDE, 0xC9, 0xB1, 0x1F, 0x64, 0x54, 0xFA, 0xD9, 0xAB, - 0x4F, 0x70, 0xBA, 0x5B, -}; -static unsigned char dh512_g[] = { - 0x02, -}; - -static unsigned char dh1024_p[] = { - 0xB0, 0xFE, 0xB4, 0xCF, 0xD4, 0x55, 0x07, 0xE7, 0xCC, 0x88, 0x59, 0x0D, - 0x17, 0x26, 0xC5, 0x0C, 0xA5, 0x4A, 0x92, 0x23, 0x81, 0x78, 0xDA, 0x88, - 0xAA, 0x4C, 0x13, 0x06, 0xBF, 0x5D, 0x2F, 0x9E, 0xBC, 0x96, 0xB8, 0x51, - 0x00, 0x9D, 0x0C, 0x0D, 0x75, 0xAD, 0xFD, 0x3B, 0xB1, 0x7E, 0x71, 0x4F, - 0x3F, 0x91, 0x54, 0x14, 0x44, 0xB8, 0x30, 0x25, 0x1C, 0xEB, 0xDF, 0x72, - 0x9C, 0x4C, 0xF1, 0x89, 0x0D, 0x68, 0x3F, 0x94, 0x8E, 0xA4, 0xFB, 0x76, - 0x89, 0x18, 0xB2, 0x91, 0x16, 0x90, 0x01, 0x99, 0x66, 0x8C, 0x53, 0x81, - 0x4E, 0x27, 0x3D, 0x99, 0xE7, 0x5A, 0x7A, 0xAF, 0xD5, 0xEC, 0xE2, 0x7E, - 0xFA, 0xED, 0x01, 0x18, 0xC2, 0x78, 0x25, 0x59, 0x06, 0x5C, 0x39, 0xF6, - 0xCD, 0x49, 0x54, 0xAF, 0xC1, 0xB1, 0xEA, 0x4A, 0xF9, 0x53, 0xD0, 0xDF, - 0x6D, 0xAF, 0xD4, 0x93, 0xE7, 0xBA, 0xAE, 0x9B, -}; - -static unsigned char dh1024_g[] = { - 0x02, -}; - diff --git a/src/path_util.c b/src/path_util.c new file mode 100644 index 0000000..ea3bba1 --- /dev/null +++ b/src/path_util.c @@ -0,0 +1,37 @@ +/* + * This file is part of the bip project + * Copyright (C) 2016 Pierre-Louis Bonicoli + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "path_util.h" +#include "util.h" + +#include +#include + +char *default_path(const char *biphome, const char *filename, const char *desc) +{ + char *conf_file; + // '/' and NULL + conf_file = bip_malloc(strlen(biphome) + strlen(filename) + 2); + strcpy(conf_file, biphome); + conf_file[strlen(biphome)] = '/'; + strcat(conf_file, filename); + mylog(LOG_INFO, "Using default %s: %s", desc, conf_file); + return conf_file; +} + +void assert_path_exists(char *path) +{ + FILE* f; + if ((f = fopen(path, "r")) == NULL) + fatal("Unable to open file %s for reading", path); + else + fclose(f); +} diff --git a/src/path_util.h b/src/path_util.h new file mode 100644 index 0000000..87cbf6f --- /dev/null +++ b/src/path_util.h @@ -0,0 +1,19 @@ +/* + * This file is part of the bip project + * Copyright (C) 2016 Pierre-Louis Bonicoli + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ +#ifndef PATH_UTIL_H +#define PATH_UTIL_H + +/* return path of filename located in bip home directory */ +char *default_path(const char *biphome, const char *filename, const char *desc); +/* exit program if path doesn't exist */ +void assert_path_exists(char *path); + +#endif