diff --git a/cfg.lex b/cfg.lex index 72406596e9c..d0ab259973b 100644 --- a/cfg.lex +++ b/cfg.lex @@ -351,6 +351,9 @@ TLS_REQUIRE_CLIENT_CERTIFICATE "tls_require_client_certificate" TLS_CERTIFICATE "tls_certificate" TLS_PRIVATE_KEY "tls_private_key" TLS_CA_LIST "tls_ca_list" +TLS_CA_DIR "tls_ca_dir" +TLS_DH_PARAMS "tls_dh_params" +TLS_EC_CURVE "tls_ec_curve" TLS_CIPHERS_LIST "tls_ciphers_list" TLS_HANDSHAKE_TIMEOUT "tls_handshake_timeout" TLS_SEND_TIMEOUT "tls_send_timeout" @@ -390,6 +393,7 @@ SSLv23 "sslv23"|"SSLv23"|"SSLV23" SSLv2 "sslv2"|"SSLv2"|"SSLV2" SSLv3 "sslv3"|"SSLv3"|"SSLV3" TLSv1 "tlsv1"|"TLSv1"|"TLSV1" +TLSv1_2 "tlsv1_2"|"TLSv1_2"|"TLSV1_2" NULLV "null"|"NULL" LETTER [a-zA-Z] @@ -660,6 +664,12 @@ IMPORTFILE "import_file" return TLS_PRIVATE_KEY; } {TLS_CA_LIST} { count(); yylval.strval=yytext; return TLS_CA_LIST; } +{TLS_CA_DIR} { count(); yylval.strval=yytext; + return TLS_CA_DIR; } +{TLS_DH_PARAMS} { count(); yylval.strval=yytext; + return TLS_DH_PARAMS; } +{TLS_EC_CURVE} { count(); yylval.strval=yytext; + return TLS_EC_CURVE; } {TLS_CIPHERS_LIST} { count(); yylval.strval=yytext; return TLS_CIPHERS_LIST; } {TLS_HANDSHAKE_TIMEOUT} { count(); yylval.strval=yytext; @@ -767,6 +777,7 @@ IMPORTFILE "import_file" {SSLv2} { count(); yylval.strval=yytext; return SSLv2; } {SSLv3} { count(); yylval.strval=yytext; return SSLv3; } {TLSv1} { count(); yylval.strval=yytext; return TLSv1; } +{TLSv1_2} { count(); yylval.strval=yytext; return TLSv1_2; } {COMMA} { count(); return COMMA; } {SEMICOLON} { count(); return SEMICOLON; } diff --git a/cfg.y b/cfg.y index 4679a430cd7..97f61e33d2e 100644 --- a/cfg.y +++ b/cfg.y @@ -72,6 +72,9 @@ * 2012-01-19 added TCP keepalive support * 2012-12-06 added event_route (razvanc) * 2013-05-23 added NAPTR lookup option (dsandras) + * 2013-09-25 added TLS_CA_DIR option (chris_secusmart) + * 2013-10-06 added TLS_DH_PARAM option (mehmet_secusmart) + * 2013-10-30 added TLS_EC_CURVE option (yrjoe_secusmart) */ @@ -386,13 +389,17 @@ extern int line; %token SSLv2 %token SSLv3 %token TLSv1 +%token TLSv1_2 %token TLS_VERIFY_CLIENT %token TLS_VERIFY_SERVER %token TLS_REQUIRE_CLIENT_CERTIFICATE %token TLS_CERTIFICATE %token TLS_PRIVATE_KEY %token TLS_CA_LIST +%token TLS_CA_DIR %token TLS_CIPHERS_LIST +%token TLS_DH_PARAMS +%token TLS_EC_CURVE %token ADVERTISED_ADDRESS %token ADVERTISED_PORT %token DISABLE_CORE @@ -1019,9 +1026,19 @@ assign_stm: DEBUG EQUAL snumber { warn("tls support not compiled in"); #endif } + | TLS_METHOD EQUAL TLSv1_2 { + #ifdef USE_TLS + tls_default_server_domain->method = + TLS_USE_TLSv1_2; + tls_default_client_domain->method = + TLS_USE_TLSv1_2; + #else + warn("tls support not compiled in"); + #endif + } | TLS_METHOD EQUAL error { #ifdef USE_TLS - yyerror("SSLv23, SSLv2, SSLv3 or TLSv1" + yyerror("SSLv23, SSLv2, SSLv3, TLSv1 or TLSv1_2" " expected"); #else warn("tls support not compiled in"); @@ -1087,6 +1104,17 @@ assign_stm: DEBUG EQUAL snumber { #endif } | TLS_CA_LIST EQUAL error { yyerror("string value expected"); } + | TLS_CA_DIR EQUAL STRING { + #ifdef USE_TLS + tls_default_server_domain->ca_directory = + $3; + tls_default_client_domain->ca_directory = + $3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_CA_DIR EQUAL error { yyerror("string value expected"); } | TLS_CIPHERS_LIST EQUAL STRING { #ifdef USE_TLS tls_default_server_domain->ciphers_list @@ -1098,6 +1126,28 @@ assign_stm: DEBUG EQUAL snumber { #endif } | TLS_CIPHERS_LIST EQUAL error { yyerror("string value expected"); } + | TLS_DH_PARAMS EQUAL STRING { + #ifdef USE_TLS + tls_default_server_domain->tmp_dh_file = + $3; + tls_default_client_domain->tmp_dh_file = + $3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_DH_PARAMS EQUAL error { yyerror("string value expected"); } + | TLS_EC_CURVE EQUAL STRING { + #ifdef USE_TLS + tls_default_server_domain->tls_ec_curve = + $3; + tls_default_client_domain->tls_ec_curve = + $3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_EC_CURVE EQUAL error { yyerror("string value expected"); } | TLS_HANDSHAKE_TIMEOUT EQUAL NUMBER { #ifdef USE_TLS tls_handshake_timeout=$3; @@ -1500,7 +1550,14 @@ tls_server_var : TLS_METHOD EQUAL SSLv23 { warn("tls support not compiled in"); #endif } - | TLS_METHOD EQUAL error { yyerror("SSLv23, SSLv2, SSLv3 or TLSv1 expected"); } + | TLS_METHOD EQUAL TLSv1_2 { + #ifdef USE_TLS + tls_server_domains->method=TLS_USE_TLSv1_2; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_METHOD EQUAL error { yyerror("SSLv23, SSLv2, SSLv3, TLSv1 or TLSV1_2 expected"); } | TLS_CERTIFICATE EQUAL STRING { #ifdef USE_TLS tls_server_domains->cert_file=$3; @@ -1527,6 +1584,14 @@ tls_server_var : TLS_METHOD EQUAL SSLv23 { #endif } | TLS_CA_LIST EQUAL error { yyerror("string value expected"); } + | TLS_CA_DIR EQUAL STRING { + #ifdef USE_TLS + tls_server_domains->ca_directory=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_CA_DIR EQUAL error { yyerror("string value expected"); } | TLS_CIPHERS_LIST EQUAL STRING { #ifdef USE_TLS tls_server_domains->ciphers_list=$3; @@ -1535,6 +1600,22 @@ tls_server_var : TLS_METHOD EQUAL SSLv23 { #endif } | TLS_CIPHERS_LIST EQUAL error { yyerror("string value expected"); } + | TLS_DH_PARAMS EQUAL STRING { + #ifdef USE_TLS + tls_server_domains->tmp_dh_file=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_DH_PARAMS EQUAL error { yyerror("string value expected"); } + | TLS_EC_CURVE EQUAL STRING { + #ifdef USE_TLS + tls_server_domains->tls_ec_curve=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_EC_CURVE EQUAL error { yyerror("string value expected"); } | TLS_VERIFY_CLIENT EQUAL NUMBER { #ifdef USE_TLS tls_server_domains->verify_cert=$3; @@ -1582,8 +1663,15 @@ tls_client_var : TLS_METHOD EQUAL SSLv23 { warn("tls support not compiled in"); #endif } + | TLS_METHOD EQUAL TLSv1_2 { + #ifdef USE_TLS + tls_client_domains->method=TLS_USE_TLSv1_2; + #else + warn("tls support not compiled in"); + #endif + } | TLS_METHOD EQUAL error { - yyerror("SSLv23, SSLv2, SSLv3 or TLSv1 expected"); } + yyerror("SSLv23, SSLv2, SSLv3, TLSv1 or TLSv1_2 expected"); } | TLS_CERTIFICATE EQUAL STRING { #ifdef USE_TLS tls_client_domains->cert_file=$3; @@ -1610,6 +1698,14 @@ tls_client_var : TLS_METHOD EQUAL SSLv23 { #endif } | TLS_CA_LIST EQUAL error { yyerror("string value expected"); } + | TLS_CA_DIR EQUAL STRING { + #ifdef USE_TLS + tls_client_domains->ca_directory=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_CA_DIR EQUAL error { yyerror("string value expected"); } | TLS_CIPHERS_LIST EQUAL STRING { #ifdef USE_TLS tls_client_domains->ciphers_list=$3; @@ -1618,6 +1714,22 @@ tls_client_var : TLS_METHOD EQUAL SSLv23 { #endif } | TLS_CIPHERS_LIST EQUAL error { yyerror("string value expected"); } + | TLS_DH_PARAMS EQUAL STRING { + #ifdef USE_TLS + tls_client_domains->tmp_dh_file=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_DH_PARAMS EQUAL error { yyerror("string value expected"); } + | TLS_EC_CURVE EQUAL STRING { + #ifdef USE_TLS + tls_client_domains->tls_ec_curve=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_EC_CURVE EQUAL error { yyerror("string value expected"); } | TLS_VERIFY_SERVER EQUAL NUMBER { #ifdef USE_TLS tls_client_domains->verify_cert=$3; diff --git a/config.h b/config.h index 95f36c97a9c..aeb3f3b22fe 100644 --- a/config.h +++ b/config.h @@ -25,6 +25,7 @@ * 2003-07-04 fixed SRV lookup prefix for TLS/sips (andrei) * 2007-02-16 Added an OPENSER_OID define to localize OpenSER's IANA assigned * OID under the enterprise branch (jmagder) + * 2013-09-17 TLS_DH_PARAMS_FILE added (mehmet) */ /*! @@ -44,7 +45,8 @@ #define TLS_PKEY_FILE CFG_DIR "tls/cert.pem" #define TLS_CERT_FILE CFG_DIR "tls/cert.pem" #define TLS_CA_FILE 0 /*!< no CA list file by default */ - +#define TLS_CA_DIRECTORY "/etc/pki/CA/" +#define TLS_DH_PARAMS_FILE 0 /*!< no DH params file by default */ #define MAX_LISTEN 16 /*!< maximum number of addresses on which we will listen */ diff --git a/tls/doc/tls.sgml b/tls/doc/tls.sgml index b185b7d628a..d551c92392c 100644 --- a/tls/doc/tls.sgml +++ b/tls/doc/tls.sgml @@ -45,6 +45,13 @@ klaus.darilion@nic.at + + Christian + Lahme +
+ christian.lahme@secusmart.com +
+
2005 @@ -58,6 +65,10 @@ 2006 enum.at + + 2013 + Secusmart GmbH + $Revision$ diff --git a/tls/doc/tls_user.sgml b/tls/doc/tls_user.sgml index f9b8db4142e..c1bbb166e71 100644 --- a/tls/doc/tls_user.sgml +++ b/tls/doc/tls_user.sgml @@ -202,7 +202,7 @@
Dependencies of external libraries - &ser; TLS support requires the following packages: + &ser; TLS v1.0 support requires the following packages: openssl or @@ -216,6 +216,21 @@ + + &ser; TLS v1.1/1.2 support requires the following packages: + + + openssl or + libssl >= 1.0.1e + + + + openssl-dev or + libssl-dev + + + +
@@ -468,6 +483,11 @@ tls_port_no = 5062 Sets the TLS protocol method which can be: + + TLSv1_2 - means &ser; will + accept only TLSv1.2 connections (rfc3261 conformant). + + TLSv1 - means &ser; will accept only TLSv1 connections (rfc3261 conformant). @@ -601,6 +621,33 @@ tls_private_key="/mycerts/private/prik.pem" ... tls_ca_list="/mycerts/certs/ca_list.pem" +... + + + + +
+ <varname>tls_ca_dir</varname>=path + + Directory storing trusted CAs. The path contains the + certificates accepted, each as hash which is linked to + certificate file. + + + See previous chapter for more + information. + + + It's usable only if TLS support was compiled. + + + Default value is "". + + + Set <varname>tls_ca_dir</varname> variable + +... +tls_ca_dir="/mycerts/certs" ... @@ -638,6 +685,48 @@ tls_ciphers_list="NULL"
+
+ <varname>tls_dh_params</varname>=file + + You can specify a file which contains Diffie-Hellman + parameters as a PEM-file. This is needed if you would like + to specify ciphers including Diffie-Hellman mode. + + + It's usable only if TLS support was compiled. + + + It defaults to not set a dh param file. + + + Set <varname>tls_dh_params</varname> variable + + +... +tls_dh_param="/etc/pki/CA/dh1024.pem" +... + + +
+ +
+ <varname>tls_ec_curve</varname>=string + + You can specify an elliptic curve which should be used for + ciphers which demand an elliptic curve. + + + It's usable only if TLS v1.1/1.2 support was compiled. + A list of curves which can be used you can get by + + openssl ecparam -list_curve + + + + It defaults to not set a elliptic curve. + +
+
<varname>tls_verify_client</varname>=number and <varname>tls_require_client_certificate</varname>=number diff --git a/tls/tls_config.c b/tls/tls_config.c index 42ccef79a47..0ee8067fe4e 100644 --- a/tls/tls_config.c +++ b/tls/tls_config.c @@ -43,6 +43,8 @@ int tls_require_client_cert = 1; char *tls_cert_file = TLS_CERT_FILE; char *tls_pkey_file = TLS_PKEY_FILE; char *tls_ca_file = TLS_CA_FILE; +char *tls_ca_dir = TLS_CA_DIRECTORY; +char *tls_tmp_dh_file = TLS_DH_PARAMS_FILE; /* defaul cipher=0, this means the DEFAULT ciphers */ char *tls_ciphers_list = 0; /* TLS timeouts; should be low to detect problems fast */ diff --git a/tls/tls_config.h b/tls/tls_config.h index 17d17d85ace..850271e2585 100644 --- a/tls/tls_config.h +++ b/tls/tls_config.h @@ -39,7 +39,10 @@ enum tls_method { TLS_USE_TLSv1, TLS_USE_SSLv23_cli, TLS_USE_SSLv23_srv, - TLS_USE_SSLv23 + TLS_USE_SSLv23, + TLS_USE_TLSv1_2_cli, + TLS_USE_TLSv1_2_srv, + TLS_USE_TLSv1_2 }; extern int tls_log; @@ -51,6 +54,8 @@ extern int tls_require_client_cert; extern char *tls_cert_file; extern char *tls_pkey_file; extern char *tls_ca_file; +extern char *tls_ca_dir; +extern char *tls_tmp_dh_file; extern char *tls_ciphers_list; extern int tls_handshake_timeout; extern int tls_send_timeout; diff --git a/tls/tls_domain.h b/tls/tls_domain.h index 148b5671e0c..2e1e1dea235 100644 --- a/tls/tls_domain.h +++ b/tls/tls_domain.h @@ -54,6 +54,9 @@ struct tls_domain { char *cert_file; char *pkey_file; char *ca_file; + char *tmp_dh_file; + char *tls_ec_curve; + char *ca_directory; char *ciphers_list; enum tls_method method; struct tls_domain *next; diff --git a/tls/tls_init.c b/tls/tls_init.c index e716f2a4e18..dcdbb888f9c 100644 --- a/tls/tls_init.c +++ b/tls/tls_init.c @@ -46,11 +46,10 @@ #define SER_SSL_SESS_ID ((unsigned char*)"opensips-tls-1.2.0") #define SER_SSL_SESS_ID_LEN (sizeof(SER_SSL_SESS_ID)-1) - -#if OPENSSL_VERSION_NUMBER < 0x00907000L +#if OPENSSL_VERSION_NUMBER < 0x10001000L #warning "" #warning "==============================================================" - #warning "Your version of OpenSSL is < 0.9.7." + #warning "Your version of OpenSSL is < 1.0.1." #warning " Upgrade for better compatibility, features and security fixes!" #warning "=============================================================" #warning "" @@ -321,6 +320,80 @@ load_ca(SSL_CTX * ctx, char *filename) } +/* + * Load a caList from a directory instead of a single file. + */ +static int +load_ca_dir(SSL_CTX * ctx, char *directory) +{ + LM_DBG("Entered\n"); + if (!SSL_CTX_load_verify_locations(ctx, 0 , directory)) { + LM_ERR("unable to load ca directory '%s'\n", directory); + return -1; + } + + LM_DBG("CA '%s' successfuly loaded from directory\n", directory); + return 0; +} + +/* + * Load and set DH params to be used in ephemeral key exchange from a file. + */ +static int +set_dh_params(SSL_CTX * ctx, char *filename) +{ + LM_DBG("Entered\n"); + BIO *bio = BIO_new_file(filename, "r"); + if (!bio) { + LM_ERR("unable to open dh params file '%s'\n", filename); + return -1; + } + + DH *dh = PEM_read_bio_DHparams(bio, 0, 0, 0); + BIO_free(bio); + if (!dh) { + LM_ERR("unable to read dh params from '%s'\n", filename); + return -1; + } + + if (!SSL_CTX_set_tmp_dh(ctx, dh)) { + LM_ERR("unable to set dh params\n"); + return -1; + } + + DH_free(dh); + LM_DBG("DH params from '%s' successfuly set\n", filename); + return 0; +} + +/* + * Set elliptic curve. + */ +static int set_ec_params(SSL_CTX * ctx, const char* curve_name) +{ + int curve = 0; + if (curve_name) { + curve = OBJ_txt2nid(curve_name); + } + if (curve > 0) { + EC_KEY *ecdh = EC_KEY_new_by_curve_name (curve); + if (! ecdh) { + LM_ERR("unable to create EC curve\n"); + return -1; + } + if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) { + LM_ERR("unable to set tmp_ecdh\n"); + return -1; + } + EC_KEY_free (ecdh); + } + else { + LM_ERR("unable to find the EC curve\n"); + return -1; + } + return 0; +} + /* * initialize ssl methods */ @@ -346,6 +419,13 @@ init_ssl_methods(void) ssl_methods[TLS_USE_SSLv23_cli - 1] = SSLv23_client_method(); ssl_methods[TLS_USE_SSLv23_srv - 1] = SSLv23_server_method(); ssl_methods[TLS_USE_SSLv23 - 1] = SSLv23_method(); + +#if OPENSSL_VERSION_NUMBER >= 0x10001000L + ssl_methods[TLS_USE_TLSv1_2_cli - 1] = TLSv1_2_client_method(); + ssl_methods[TLS_USE_TLSv1_2_srv - 1] = TLSv1_2_server_method(); + ssl_methods[TLS_USE_TLSv1_2 - 1] = TLSv1_2_method(); +#endif + } @@ -356,6 +436,28 @@ init_ssl_methods(void) static int init_ssl_ctx_behavior( struct tls_domain *d ) { int verify_mode; + + /* + * set dh params + */ + if (!d->tmp_dh_file) { + LM_NOTICE("no DH params file for tls[%s:%d] defined, " + "using default '%s'\n", ip_addr2a(&d->addr), d->port, + tls_tmp_dh_file); + d->tmp_dh_file = tls_tmp_dh_file; + } + if (d->tmp_dh_file && set_dh_params(d->ctx, d->tmp_dh_file) < 0) + return -1; + + if (d->tls_ec_curve) { + if (set_ec_params(d->ctx, d->tls_ec_curve) < 0) { + return -1; + } + } + else { + LM_NOTICE("No EC curve defined\n"); + } + if( d->ciphers_list != 0 ) { if( SSL_CTX_set_cipher_list(d->ctx, d->ciphers_list) == 0 ) { LM_ERR("failure to set SSL context " @@ -729,6 +831,21 @@ init_tls_domains(struct tls_domain *d) } if (d->ca_file && load_ca(d->ctx, d->ca_file) < 0) return -1; + + /* + * load ca from directory + */ + if (!d->ca_directory) { + + LM_NOTICE("no CA for tls[%s:%d] defined, " + "using default '%s'\n", ip_addr2a(&d->addr), d->port, + tls_ca_dir); + d->ca_directory = tls_ca_dir; + } + + if (d->ca_directory && load_ca_dir(d->ctx, d->ca_directory) < 0) + return -1; + d = d->next; }