diff options
Diffstat (limited to 'radsecproxy.c')
-rw-r--r-- | radsecproxy.c | 190 |
1 files changed, 108 insertions, 82 deletions
diff --git a/radsecproxy.c b/radsecproxy.c index cc0dd03..af94af3 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -81,6 +81,8 @@ static long *ssl_lock_count; extern int optind; extern char *optarg; +SSL_CTX *tlsgetctx(struct tls *t); + /* callbacks for making OpenSSL thread safe */ unsigned long ssl_thread_id() { return (unsigned long)pthread_self(); @@ -783,6 +785,7 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) { struct timeval now; time_t elapsed; X509 *cert; + SSL_CTX *ctx = NULL; debug(DBG_DBG, "tlsconnect called from %s", text); pthread_mutex_lock(&server->lock); @@ -793,7 +796,7 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) { return; } - debug(DBG_DBG, "tlsconnect %s", text); + debug(DBG_DBG, "tlsconnect(%s)", text); for (;;) { gettimeofday(&now, NULL); @@ -820,7 +823,14 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) { } SSL_free(server->ssl); - server->ssl = SSL_new(server->conf->ssl_ctx); + server->ssl = NULL; + ctx = tlsgetctx(server->conf->tlsconf); + if (!ctx) + continue; + server->ssl = SSL_new(ctx); + if (!server->ssl) + continue; + SSL_set_fd(server->ssl, server->sock); if (SSL_connect(server->ssl) <= 0) continue; @@ -834,6 +844,7 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) { X509_free(cert); } debug(DBG_WARN, "tlsconnect: TLS connection to %s port %s up", server->conf->host, server->conf->port); + server->connectionok = 1; gettimeofday(&server->lastconnecttry, NULL); pthread_mutex_unlock(&server->lock); } @@ -917,19 +928,17 @@ int clientradputtls(struct server *server, unsigned char *rad) { int cnt; size_t len; unsigned long error; - struct timeval lastconnecttry; struct clsrvconf *conf = server->conf; - + + if (!server->connectionok) + return 0; len = RADLEN(rad); - lastconnecttry = server->lastconnecttry; - while ((cnt = SSL_write(server->ssl, rad, len)) <= 0) { + if ((cnt = SSL_write(server->ssl, rad, len)) <= 0) { while ((error = ERR_get_error())) debug(DBG_ERR, "clientradputtls: TLS: %s", ERR_error_string(error, NULL)); - tlsconnect(server, &lastconnecttry, "clientradputtls"); - lastconnecttry = server->lastconnecttry; + return 0; } - server->connectionok = 1; debug(DBG_DBG, "clientradputtls: Sent %d bytes, Radius packet of length %d to TLS peer %s", cnt, len, conf->host); return 1; } @@ -2221,6 +2230,7 @@ void *clientwr(void *arg) { int i; uint8_t rnd; struct timeval now, lastsend; + time_t secs; struct timespec timeout; struct request statsrvrq; unsigned char statsrvbuf[38]; @@ -2254,8 +2264,9 @@ void *clientwr(void *arg) { /* random 0-7 seconds */ RAND_bytes(&rnd, 1); rnd /= 32; - if (!timeout.tv_sec || timeout.tv_sec > lastsend.tv_sec + STATUS_SERVER_PERIOD + rnd) - timeout.tv_sec = lastsend.tv_sec + STATUS_SERVER_PERIOD + rnd; + secs = now.tv_sec - lastsend.tv_sec < STATUS_SERVER_PERIOD ? lastsend.tv_sec : now.tv_sec; + if (!timeout.tv_sec || timeout.tv_sec > secs + STATUS_SERVER_PERIOD + rnd) + timeout.tv_sec = secs + STATUS_SERVER_PERIOD + rnd; } if (timeout.tv_sec) { debug(DBG_DBG, "clientwr: waiting up to %ld secs for new request", timeout.tv_sec - now.tv_sec); @@ -2334,7 +2345,7 @@ void *clientwr(void *arg) { clientradput(server, server->requests[i].buf); gettimeofday(&lastsend, NULL); } - if (server->conf->statusserver) { + if (server->conf->statusserver && server->connectionok) { gettimeofday(&now, NULL); if (now.tv_sec - lastsend.tv_sec >= STATUS_SERVER_PERIOD) { if (!RAND_bytes(statsrvbuf + 4, 16)) { @@ -2505,6 +2516,7 @@ void *tlsservernew(void *arg) { struct list_node *cur = NULL; SSL *ssl = NULL; X509 *cert = NULL; + SSL_CTX *ctx = NULL; unsigned long error; struct client *client; @@ -2517,7 +2529,12 @@ void *tlsservernew(void *arg) { conf = find_conf('T', (struct sockaddr *)&from, clconfs, &cur); if (conf) { - ssl = SSL_new(conf->ssl_ctx); + ctx = tlsgetctx(conf->tlsconf); + if (!ctx) + goto exit; + ssl = SSL_new(ctx); + if (!ssl) + goto exit; SSL_set_fd(ssl, s); if (SSL_accept(ssl) <= 0) { @@ -2593,20 +2610,13 @@ int tlslistener() { return 0; } -void tlsadd(char *value, char *cacertfile, char *cacertpath, char *certfile, char *certkeyfile, char *certkeypwd, uint8_t crlcheck) { - struct tls *new; - SSL_CTX *ctx; +SSL_CTX *tlscreatectx(struct tls *conf) { + SSL_CTX *ctx = NULL; STACK_OF(X509_NAME) *calist; X509_STORE *x509_s; int i; unsigned long error; - if (!certfile || !certkeyfile) - debugx(1, DBG_ERR, "TLSCertificateFile and TLSCertificateKeyFile must be specified in TLS context %s", value); - - if (!cacertfile && !cacertpath) - debugx(1, DBG_ERR, "CA Certificate file or path need to be specified in TLS context %s", value); - if (!ssl_locks) { ssl_locks = calloc(CRYPTO_num_locks(), sizeof(pthread_mutex_t)); ssl_lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long)); @@ -2627,26 +2637,34 @@ void tlsadd(char *value, char *cacertfile, char *cacertpath, char *certfile, cha RAND_seed((unsigned char *)&pid, sizeof(pid)); } } + ctx = SSL_CTX_new(TLSv1_method()); - if (certkeypwd) { - SSL_CTX_set_default_passwd_cb_userdata(ctx, certkeypwd); + if (!ctx) { + debug(DBG_ERR, "tlscreatectx: Error initialising SSL/TLS in TLS context %s", conf->name); + return NULL; + } + + if (conf->certkeypwd) { + SSL_CTX_set_default_passwd_cb_userdata(ctx, conf->certkeypwd); SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb); } - if (!SSL_CTX_use_certificate_chain_file(ctx, certfile) || - !SSL_CTX_use_PrivateKey_file(ctx, certkeyfile, SSL_FILETYPE_PEM) || + if (!SSL_CTX_use_certificate_chain_file(ctx, conf->certfile) || + !SSL_CTX_use_PrivateKey_file(ctx, conf->certkeyfile, SSL_FILETYPE_PEM) || !SSL_CTX_check_private_key(ctx) || - !SSL_CTX_load_verify_locations(ctx, cacertfile, cacertpath)) { + !SSL_CTX_load_verify_locations(ctx, conf->cacertfile, conf->cacertpath)) { while ((error = ERR_get_error())) debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL)); - debugx(1, DBG_ERR, "Error initialising SSL/TLS in TLS context %s", value); + debug(DBG_ERR, "tlscreatectx: error initialising SSL/TLS in TLS context %s", conf->name); + SSL_CTX_free(ctx); + return NULL; } - calist = cacertfile ? SSL_load_client_CA_file(cacertfile) : NULL; - if (!cacertfile || calist) { - if (cacertpath) { + calist = conf->cacertfile ? SSL_load_client_CA_file(conf->cacertfile) : NULL; + if (!conf->cacertfile || calist) { + if (conf->cacertpath) { if (!calist) calist = sk_X509_NAME_new_null(); - if (!SSL_add_dir_cert_subjects_to_stack(calist, cacertpath)) { + if (!SSL_add_dir_cert_subjects_to_stack(calist, conf->cacertpath)) { sk_X509_NAME_free(calist); calist = NULL; } @@ -2655,7 +2673,9 @@ void tlsadd(char *value, char *cacertfile, char *cacertpath, char *certfile, cha if (!calist) { while ((error = ERR_get_error())) debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL)); - debugx(1, DBG_ERR, "Error adding CA subjects in TLS context %s", value); + debug(DBG_ERR, "tlscreatectx: error initialising SSL/TLS in TLS context %s", conf->name); + SSL_CTX_free(ctx); + return NULL; } ERR_clear_error(); /* add_dir_cert_subj returns errors on success */ SSL_CTX_set_client_CA_list(ctx, calist); @@ -2663,40 +2683,16 @@ void tlsadd(char *value, char *cacertfile, char *cacertpath, char *certfile, cha SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb); SSL_CTX_set_verify_depth(ctx, MAX_CERT_DEPTH + 1); - if (crlcheck) { + if (conf->crlcheck) { x509_s = SSL_CTX_get_cert_store(ctx); X509_STORE_set_flags(x509_s, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); } - - new = malloc(sizeof(struct tls)); - if (!new || !list_push(tlsconfs, new)) - debugx(1, DBG_ERR, "malloc failed"); - memset(new, 0, sizeof(struct tls)); - new->name = stringcopy(value, 0); - if (!new->name) - debugx(1, DBG_ERR, "malloc failed"); - new->ctx = ctx; - new->count = 0; - debug(DBG_DBG, "tlsadd: added TLS context %s", value); + debug(DBG_DBG, "tlscreatectx: created tls context %s", conf->name); + return ctx; } -void tlsfree() { - struct list_node *entry; - struct tls *t; - - for (entry = list_first(tlsconfs); entry; entry = list_next(entry)) { - t = (struct tls *)entry->data; - if (t->name) - free(t->name); - if (!t->count) - SSL_CTX_free(t->ctx); - } - list_destroy(tlsconfs); - tlsconfs = NULL; -} - -SSL_CTX *tlsgetctx(char *alt1, char *alt2) { +struct tls *tlsgettls(char *alt1, char *alt2) { struct list_node *entry; struct tls *t, *t1 = NULL, *t2 = NULL; @@ -2710,10 +2706,27 @@ SSL_CTX *tlsgetctx(char *alt1, char *alt2) { t2 = t; } - t = (t1 ? t1 : t2); + return t1 ? t1 : t2; +} + +SSL_CTX *tlsgetctx(struct tls *t) { + struct timeval now; + if (!t) return NULL; - t->count++; + gettimeofday(&now, NULL); + if (t->expiry && t->ctx) { + if (t->expiry < now.tv_sec) { + t->expiry = now.tv_sec + t->cacheexpiry; + SSL_CTX_free(t->ctx); + return t->ctx = tlscreatectx(t); + } + } + if (!t->ctx) { + t->ctx = tlscreatectx(t); + if (t->cacheexpiry) + t->expiry = now.tv_sec + t->cacheexpiry; + } return t->ctx; } @@ -3112,8 +3125,8 @@ void confclient_cb(struct gconffile **cf, char *block, char *opt, char *val) { conf->type = 'U'; client_udp_count++; } else if (type && !strcasecmp(type, "tls")) { - conf->ssl_ctx = tls ? tlsgetctx(tls, NULL) : tlsgetctx("defaultclient", "default"); - if (!conf->ssl_ctx) + conf->tlsconf = tls ? tlsgettls(tls, NULL) : tlsgettls("defaultclient", "default"); + if (!conf->tlsconf) debugx(1, DBG_ERR, "error in block %s, no tls context defined", block); if (matchcertattr && !addmatchcertattr(conf, matchcertattr)) debugx(1, DBG_ERR, "error in block %s, invalid MatchCertificateAttributeValue", block); @@ -3194,8 +3207,8 @@ void confserver_cb(struct gconffile **cf, char *block, char *opt, char *val) { if (!conf->port) conf->port = stringcopy(DEFAULT_UDP_PORT, 0); } else if (type && !strcasecmp(type, "tls")) { - conf->ssl_ctx = tls ? tlsgetctx(tls, NULL) : tlsgetctx("defaultserver", "default"); - if (!conf->ssl_ctx) + conf->tlsconf = tls ? tlsgettls(tls, NULL) : tlsgettls("defaultserver", "default"); + if (!conf->tlsconf) debugx(1, DBG_ERR, "error in block %s, no tls context defined", block); if (matchcertattr && !addmatchcertattr(conf, matchcertattr)) debugx(1, DBG_ERR, "error in block %s, invalid MatchCertificateAttributeValue", block); @@ -3263,27 +3276,41 @@ void confrealm_cb(struct gconffile **cf, char *block, char *opt, char *val) { } void conftls_cb(struct gconffile **cf, char *block, char *opt, char *val) { - char *cacertfile = NULL, *cacertpath = NULL, *certfile = NULL, *certkeyfile = NULL, *certkeypwd = NULL; - uint8_t crlcheck = 0; + struct tls *conf; + long int expiry = LONG_MIN; debug(DBG_DBG, "conftls_cb called for %s", block); + + conf = malloc(sizeof(struct tls)); + if (!conf) + debugx(1, DBG_ERR, "conftls_cb: malloc failed"); + memset(conf, 0, sizeof(struct tls)); getgenericconfig(cf, block, - "CACertificateFile", CONF_STR, &cacertfile, - "CACertificatePath", CONF_STR, &cacertpath, - "CertificateFile", CONF_STR, &certfile, - "CertificateKeyFile", CONF_STR, &certkeyfile, - "CertificateKeyPassword", CONF_STR, &certkeypwd, - "CRLCheck", CONF_BLN, &crlcheck, + "CACertificateFile", CONF_STR, &conf->cacertfile, + "CACertificatePath", CONF_STR, &conf->cacertpath, + "CertificateFile", CONF_STR, &conf->certfile, + "CertificateKeyFile", CONF_STR, &conf->certkeyfile, + "CertificateKeyPassword", CONF_STR, &conf->certkeypwd, + "CacheExpiry", CONF_LINT, &expiry, + "CRLCheck", CONF_BLN, &conf->crlcheck, NULL ); - tlsadd(val, cacertfile, cacertpath, certfile, certkeyfile, certkeypwd, crlcheck); - free(cacertfile); - free(cacertpath); - free(certfile); - free(certkeyfile); - free(certkeypwd); + if (!conf->certfile || !conf->certkeyfile) + debugx(1, DBG_ERR, "conftls_cb: TLSCertificateFile and TLSCertificateKeyFile must be specified in block %s", val); + if (!conf->cacertfile && !conf->cacertpath) + debugx(1, DBG_ERR, "CA Certificate file or path need to be specified in TLS context %s", val); + if (expiry != LONG_MIN) { + if (expiry < 0) + debugx(1, DBG_ERR, "error in block %s, value of option CacheExpiry is %ld, may not be negative", val, expiry); + conf->cacheexpiry = expiry; + } + conf->name = stringcopy(val, 0); + if (!conf->name || !list_push(tlsconfs, conf)) + debugx(1, DBG_ERR, "conftls_cb: malloc failed"); + + debug(DBG_DBG, "conftls_cb: added TLS block %s", val); } void confrewrite_cb(struct gconffile **cf, char *block, char *opt, char *val) { @@ -3344,7 +3371,6 @@ void getmainconfig(const char *configfile) { "Rewrite", CONF_CBK, confrewrite_cb, NULL ); - tlsfree(); rewritefree(); if (loglevel != LONG_MIN) { |