From 5503634c4e796410464484e5e9fb210e906a204d Mon Sep 17 00:00:00 2001 From: Bogdan Chifor Date: Mon, 24 Aug 2015 22:43:32 +0300 Subject: [PATCH] Add CRL (Certificate Revocation List) verification for TLS CRL verification was added in the proto tls module. By adding this feature revoked client certificates can be detected during the TLS process, thus permitting a robust security mechanism. The following parameters where added to the proto tls module in the configuration script: crl_dir and crl_check_all. The crl_dir parameter specifies the directory which contains the CRL files (multiple CRL files can be added). The crl_check_all parameter must be 0 or 1 and specifies whether all the certificates from the chain are verified against a CRL or not. By default, CRL verification is enabled only for client certificates (or when crl_check_all is 0). If crl_check_all is 1 then the issuer (chain) certificates are also verified against the given CRL files. --- modules/proto_tls/proto_tls.c | 94 ++++++++++++++++++++++++++++++++++ modules/proto_tls/tls_config.c | 2 + modules/proto_tls/tls_config.h | 1 + modules/proto_tls/tls_domain.c | 1 + modules/proto_tls/tls_domain.h | 2 + modules/proto_tls/tls_params.c | 27 ++++++++++ modules/proto_tls/tls_params.h | 4 ++ 7 files changed, 131 insertions(+) diff --git a/modules/proto_tls/proto_tls.c b/modules/proto_tls/proto_tls.c index 205463d0694..24fe438d85e 100644 --- a/modules/proto_tls/proto_tls.c +++ b/modules/proto_tls/proto_tls.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "../../dprint.h" #include "../../mem/shm_mem.h" @@ -127,6 +128,8 @@ static param_export_t params[] = { { "require_cert", STR_PARAM|USE_FUNC_PARAM, (void*)tlsp_set_require }, { "certificate", STR_PARAM|USE_FUNC_PARAM, (void*)tlsp_set_certificate}, { "private_key", STR_PARAM|USE_FUNC_PARAM, (void*)tlsp_set_pk }, + { "crl_check_all", STR_PARAM|USE_FUNC_PARAM, (void*)tlsp_set_crl_check }, + { "crl_dir", STR_PARAM|USE_FUNC_PARAM, (void*)tlsp_set_crldir }, { "ca_list", STR_PARAM|USE_FUNC_PARAM, (void*)tlsp_set_calist }, { "ca_dir", STR_PARAM|USE_FUNC_PARAM, (void*)tlsp_set_cadir }, { "ciphers_list", STR_PARAM|USE_FUNC_PARAM, (void*)tlsp_set_cplist }, @@ -832,6 +835,87 @@ static int load_certificate(SSL_CTX * ctx, char *filename) return 0; } +static int load_crl(SSL_CTX * ctx, char *crl_directory, int crl_check_all) +{ + DIR *d; + struct dirent *dir; + int crl_added = 0; + LM_DBG("Loading CRL from directory\n"); + + /*Get X509 store from SSL context*/ + X509_STORE *store = SSL_CTX_get_cert_store(ctx); + if(!store) { + LM_ERR("Unable to get X509 store from ssl context\n"); + return -1; + } + + /*Parse directory*/ + d = opendir(crl_directory); + if(!d) { + LM_ERR("Unable to open crl directory '%s'\n", crl_directory); + return -1; + } + + while ((dir = readdir(d)) != NULL) { + /*Skip if not regular file*/ + if (dir->d_type != DT_REG) + continue; + + /*Create filename*/ + char* filename = (char*) pkg_malloc(sizeof(char)*(strlen(crl_directory)+strlen(dir->d_name)+2)); + if (!filename) { + LM_ERR("Unable to allocate crl filename\n"); + closedir(d); + return -1; + } + strcpy(filename,crl_directory); + if(filename[strlen(filename)-1] != '/') + strcat(filename,"/"); + strcat(filename,dir->d_name); + + /*Get CRL content*/ + FILE *fp = fopen(filename,"r"); + pkg_free(filename); + if(!fp) + continue; + + X509_CRL *crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL); + fclose(fp); + if(!crl) + continue; + + /*Add CRL to X509 store*/ + if (X509_STORE_add_crl(store, crl) == 1) + crl_added++; + else + LM_ERR("Unable to add crl to ssl context\n"); + + X509_CRL_free(crl); + } + closedir(d); + + if (!crl_added) { + LM_ERR("No suitable CRL files found in directory %s\n", crl_directory); + return -1; + } + + /*Enable CRL checking*/ + X509_VERIFY_PARAM *param; + param = X509_VERIFY_PARAM_new(); + + int flags = X509_V_FLAG_CRL_CHECK; + if(crl_check_all) + flags |= X509_V_FLAG_CRL_CHECK_ALL; + + X509_VERIFY_PARAM_set_flags(param, flags); + + SSL_CTX_set1_param(ctx, param); + X509_VERIFY_PARAM_free(param); + + return 0; +} + + /* * Load a caList, to be used to verify the client's certificate. @@ -980,6 +1064,16 @@ static int init_tls_domains(struct tls_domain *d) if (load_certificate(d->ctx, d->cert_file) < 0) return -1; + /** + * load crl from directory + */ + if (!d->crl_directory) { + LM_NOTICE("no crl for tls, using none"); + } else { + if(load_crl(d->ctx, d->crl_directory, d->crl_check_all) < 0) + return -1; + } + /* * load ca */ diff --git a/modules/proto_tls/tls_config.c b/modules/proto_tls/tls_config.c index 2e4ba29dbe4..86ea9de9e3b 100644 --- a/modules/proto_tls/tls_config.c +++ b/modules/proto_tls/tls_config.c @@ -48,6 +48,8 @@ int tls_method = TLS_USE_SSLv23; int tls_verify_client_cert = 1; int tls_verify_server_cert = 1; int tls_require_client_cert = 1; +/* disable CRL validation for all the certificates from the chain */ +int crl_check_all = 0; /* default location of certificates */ char *tls_cert_file = TLS_CERT_FILE; char *tls_pkey_file = TLS_PKEY_FILE; diff --git a/modules/proto_tls/tls_config.h b/modules/proto_tls/tls_config.h index cedcbfc3373..6e093278549 100644 --- a/modules/proto_tls/tls_config.h +++ b/modules/proto_tls/tls_config.h @@ -53,6 +53,7 @@ extern int tls_method; extern int tls_verify_client_cert; extern int tls_verify_server_cert; extern int tls_require_client_cert; +extern int crl_check_all; extern char *tls_cert_file; extern char *tls_pkey_file; extern char *tls_ca_file; diff --git a/modules/proto_tls/tls_domain.c b/modules/proto_tls/tls_domain.c index 20c5bc5c554..90695d4c228 100644 --- a/modules/proto_tls/tls_domain.c +++ b/modules/proto_tls/tls_domain.c @@ -216,6 +216,7 @@ struct tls_domain *tls_new_domain( str *id, int type) memcpy( d->id.s, id->s, id->len); d->type = type; + d->crl_check_all = crl_check_all; if (type & TLS_DOMAIN_SRV) { d->verify_cert = tls_verify_client_cert; diff --git a/modules/proto_tls/tls_domain.h b/modules/proto_tls/tls_domain.h index 5c051558c92..1f103b2b46a 100644 --- a/modules/proto_tls/tls_domain.h +++ b/modules/proto_tls/tls_domain.h @@ -63,8 +63,10 @@ struct tls_domain { SSL_CTX *ctx; int verify_cert; int require_client_cert; + int crl_check_all; char *cert_file; char *pkey_file; + char *crl_directory; char *ca_file; char *tmp_dh_file; char *tls_ec_curve; diff --git a/modules/proto_tls/tls_params.c b/modules/proto_tls/tls_params.c index 2b7e6be332c..14475ebd7a7 100644 --- a/modules/proto_tls/tls_params.c +++ b/modules/proto_tls/tls_params.c @@ -253,6 +253,33 @@ int tlsp_set_require(modparam_t type, void *in) return 1; } +int tlsp_set_crl_check(modparam_t type, void *in) +{ + str id; + str val; + unsigned int check; + + split_param_val( (char*)in, &id, &val); + + if (str2int( &val, &check)!=0) { + LM_ERR("option is not a number [%s]\n",val.s); + return -1; + } + + set_domain_attr( id, crl_check_all, check); + return 1; +} + +int tlsp_set_crldir(modparam_t type, void *in) +{ + str id; + str val; + + split_param_val( (char*)in, &id, &val); + + set_domain_attr( id, crl_directory, val.s); + return 1; +} int tlsp_set_certificate(modparam_t type, void *in) { diff --git a/modules/proto_tls/tls_params.h b/modules/proto_tls/tls_params.h index 850f288ab3e..ce6eb15f105 100644 --- a/modules/proto_tls/tls_params.h +++ b/modules/proto_tls/tls_params.h @@ -52,10 +52,14 @@ int tlsp_set_verify(modparam_t type, void *val); int tlsp_set_require(modparam_t type, void *val); +int tlsp_set_crl_check(modparam_t type, void *val); + int tlsp_set_certificate(modparam_t type, void *val); int tlsp_set_pk(modparam_t type, void *val); +int tlsp_set_crldir(modparam_t type, void *val); + int tlsp_set_calist(modparam_t type, void *val); int tlsp_set_cadir(modparam_t type, void *val);