summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--radsecproxy.c204
-rw-r--r--radsecproxy.conf-example51
-rw-r--r--radsecproxy.h12
3 files changed, 184 insertions, 83 deletions
diff --git a/radsecproxy.c b/radsecproxy.c
index 70ad109..33f5acf 100644
--- a/radsecproxy.c
+++ b/radsecproxy.c
@@ -50,6 +50,7 @@ static struct options options;
static struct client *clients = NULL;
static struct server *servers = NULL;
static struct realm *realms = NULL;
+static struct tls *tls = NULL;
static int client_udp_count = 0;
static int client_tls_count = 0;
@@ -58,6 +59,7 @@ static int server_udp_count = 0;
static int server_tls_count = 0;
static int server_count = 0;
static int realm_count = 0;
+static int tls_count = 0;
static struct peer *tcp_server_listen;
static struct peer *udp_server_listen;
@@ -65,7 +67,6 @@ static struct replyq udp_server_replyq;
static int udp_server_sock = -1;
static pthread_mutex_t *ssl_locks;
static long *ssl_lock_count;
-static SSL_CTX *ssl_ctx = NULL;
extern int optind;
extern char *optarg;
@@ -132,56 +133,6 @@ static int verify_cb(int ok, X509_STORE_CTX *ctx) {
return ok;
}
-SSL_CTX *ssl_init() {
- SSL_CTX *ctx;
- int i;
- unsigned long error;
-
- if (!options.tlscertificatefile || !options.tlscertificatekeyfile)
- debugx(1, DBG_ERR, "TLSCertificateFile and TLSCertificateKeyFile must be specified for TLS");
-
- if (!options.tlscacertificatefile && !options.tlscacertificatepath)
- debugx(1, DBG_ERR, "CA Certificate file/path need to be configured");
-
- ssl_locks = malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
- ssl_lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
- for (i = 0; i < CRYPTO_num_locks(); i++) {
- ssl_lock_count[i] = 0;
- pthread_mutex_init(&ssl_locks[i], NULL);
- }
- CRYPTO_set_id_callback(ssl_thread_id);
- CRYPTO_set_locking_callback(ssl_locking_callback);
-
- SSL_load_error_strings();
- SSL_library_init();
-
- while (!RAND_status()) {
- time_t t = time(NULL);
- pid_t pid = getpid();
- RAND_seed((unsigned char *)&t, sizeof(time_t));
- RAND_seed((unsigned char *)&pid, sizeof(pid));
- }
-
- ctx = SSL_CTX_new(TLSv1_method());
- if (options.tlscertificatekeypassword) {
- SSL_CTX_set_default_passwd_cb_userdata(ctx, options.tlscertificatekeypassword);
- SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
- }
- if (SSL_CTX_use_certificate_chain_file(ctx, options.tlscertificatefile) &&
- SSL_CTX_use_PrivateKey_file(ctx, options.tlscertificatekeyfile, SSL_FILETYPE_PEM) &&
- SSL_CTX_check_private_key(ctx) &&
- SSL_CTX_load_verify_locations(ctx, options.tlscacertificatefile, options.tlscacertificatepath)) {
- 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);
- return ctx;
- }
-
- while ((error = ERR_get_error()))
- debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
- debug(DBG_ERR, "Error initialising SSL/TLS");
- exit(1);
-}
-
#ifdef DEBUG
void printauth(char *s, unsigned char *t) {
int i;
@@ -461,7 +412,7 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) {
}
SSL_free(server->peer.ssl);
- server->peer.ssl = SSL_new(ssl_ctx);
+ server->peer.ssl = SSL_new(server->peer.ssl_ctx);
SSL_set_fd(server->peer.ssl, server->sock);
if (SSL_connect(server->peer.ssl) > 0 && tlsverifycert(&server->peer))
break;
@@ -1702,7 +1653,7 @@ int tlslistener() {
close(snew);
continue;
}
- client->peer.ssl = SSL_new(ssl_ctx);
+ client->peer.ssl = SSL_new(client->peer.ssl_ctx);
SSL_set_fd(client->peer.ssl, snew);
if (pthread_create(&tlsserverth, NULL, tlsserverrd, (void *)client)) {
debug(DBG_ERR, "tlslistener: pthread_create failed");
@@ -1717,6 +1668,97 @@ int tlslistener() {
return 0;
}
+void tlsadd(char *value, char *cacertfile, char *cacertpath, char *certfile, char *certkeyfile, char *certkeypwd) {
+ struct tls *new;
+ SSL_CTX *ctx;
+ 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 = malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
+ ssl_lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
+ for (i = 0; i < CRYPTO_num_locks(); i++) {
+ ssl_lock_count[i] = 0;
+ pthread_mutex_init(&ssl_locks[i], NULL);
+ }
+ CRYPTO_set_id_callback(ssl_thread_id);
+ CRYPTO_set_locking_callback(ssl_locking_callback);
+
+ SSL_load_error_strings();
+ SSL_library_init();
+
+ while (!RAND_status()) {
+ time_t t = time(NULL);
+ pid_t pid = getpid();
+ RAND_seed((unsigned char *)&t, sizeof(time_t));
+ RAND_seed((unsigned char *)&pid, sizeof(pid));
+ }
+ }
+ ctx = SSL_CTX_new(TLSv1_method());
+ if (certkeypwd) {
+ SSL_CTX_set_default_passwd_cb_userdata(ctx, 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) ||
+ !SSL_CTX_check_private_key(ctx) ||
+ !SSL_CTX_load_verify_locations(ctx, cacertfile, 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);
+ }
+
+ 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);
+
+ tls_count++;
+ tls = realloc(tls, tls_count * sizeof(struct tls));
+ if (!tls)
+ debugx(1, DBG_ERR, "malloc failed");
+ new = tls + tls_count - 1;
+ 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);
+}
+
+void tlsfree() {
+ int i;
+ for (i = 0; i < tls_count; i++)
+ if (!tls[i].count)
+ SSL_CTX_free(tls[i].ctx);
+ tls_count = 0;
+ free(tls);
+ tls = NULL;
+}
+
+SSL_CTX *tlsgetctx(char *alt1, char *alt2) {
+ int i, c1 = -1, c2 = -1;
+ for (i = 0; i < tls_count; i++) {
+ if (!strcasecmp(tls[i].name, alt1)) {
+ c1 = i;
+ break;
+ }
+ if (c2 == -1 && alt2 && !strcasecmp(tls[i].name, alt2))
+ c2 = i;
+ }
+
+ i = (c1 == -1 ? c2 : c1);
+ if (i == -1)
+ return NULL;
+ tls[i].count++;
+ return tls[i].ctx;
+}
+
void addrealm(char *value, char *server, char *message) {
int i, n;
struct realm *realm;
@@ -2011,12 +2053,12 @@ void getgeneralconfig(FILE *f, char *block, ...) {
}
void confclsrv_cb(FILE *f, char *opt, char *val) {
- char *type = NULL, *secret = NULL, *port = NULL, *statusserver = NULL;
+ char *type = NULL, *secret = NULL, *port = NULL, *tls = NULL, *statusserver = NULL;
char *block;
struct client *client = NULL;
struct server *server = NULL;
struct peer *peer;
-
+
block = malloc(strlen(opt) + strlen(val) + 2);
if (!block)
debugx(1, DBG_ERR, "malloc failed");
@@ -2027,6 +2069,7 @@ void confclsrv_cb(FILE *f, char *opt, char *val) {
getgeneralconfig(f, block,
"type", CONF_STR, &type,
"secret", CONF_STR, &secret,
+ "tls", CONF_STR, &tls,
NULL
);
client_count++;
@@ -2041,6 +2084,7 @@ void confclsrv_cb(FILE *f, char *opt, char *val) {
"type", CONF_STR, &type,
"secret", CONF_STR, &secret,
"port", CONF_STR, &port,
+ "tls", CONF_STR, &tls,
"StatusServer", CONF_STR, &statusserver,
NULL
);
@@ -2073,14 +2117,18 @@ void confclsrv_cb(FILE *f, char *opt, char *val) {
peer->port = stringcopy(DEFAULT_UDP_PORT, 0);
}
} else if (type && !strcasecmp(type, "tls")) {
- peer->type = 'T';
- if (client)
+ if (client) {
+ peer->ssl_ctx = tls ? tlsgetctx(tls, NULL) : tlsgetctx("defaultclient", "default");
client_tls_count++;
- else {
+ } else {
+ peer->ssl_ctx = tls ? tlsgetctx(tls, NULL) : tlsgetctx("defaultserver", "default");
server_tls_count++;
if (!port)
peer->port = stringcopy(DEFAULT_TLS_PORT, 0);
}
+ if (!peer->ssl_ctx)
+ debugx(1, DBG_ERR, "error in block %s, no tls context defined", block);
+ peer->type = 'T';
} else
debugx(1, DBG_ERR, "error in block %s, type must be set to UDP or TLS", block);
free(type);
@@ -2146,6 +2194,34 @@ void confrealm_cb(FILE *f, char *opt, char *val) {
free(block);
}
+void conftls_cb(FILE *f, char *opt, char *val) {
+ char *cacertfile = NULL, *cacertpath = NULL, *certfile = NULL, *certkeyfile = NULL, *certkeypwd = NULL;
+ char *block;
+
+ block = malloc(strlen(opt) + strlen(val) + 2);
+ if (!block)
+ debugx(1, DBG_ERR, "malloc failed");
+ sprintf(block, "%s %s", opt, val);
+ debug(DBG_DBG, "conftls_cb called for %s", block);
+
+ getgeneralconfig(f, block,
+ "CACertificateFile", CONF_STR, &cacertfile,
+ "CACertificatePath", CONF_STR, &cacertpath,
+ "CertificateFile", CONF_STR, &certfile,
+ "CertificateKeyFile", CONF_STR, &certkeyfile,
+ "CertificateKeyPassword", CONF_STR, &certkeypwd,
+ NULL
+ );
+
+ tlsadd(val, cacertfile, cacertpath, certfile, certkeyfile, certkeypwd);
+ free(cacertfile);
+ free(cacertpath);
+ free(certfile);
+ free(certkeyfile);
+ free(certkeypwd);
+ free(block);
+}
+
void getmainconfig(const char *configfile) {
FILE *f;
char *loglevel = NULL;
@@ -2154,11 +2230,6 @@ void getmainconfig(const char *configfile) {
memset(&options, 0, sizeof(options));
getgeneralconfig(f, NULL,
- "TLSCACertificateFile", CONF_STR, &options.tlscacertificatefile,
- "TLSCACertificatePath", CONF_STR, &options.tlscacertificatepath,
- "TLSCertificateFile", CONF_STR, &options.tlscertificatefile,
- "TLSCertificateKeyFile", CONF_STR, &options.tlscertificatekeyfile,
- "TLSCertificateKeyPassword", CONF_STR, &options.tlscertificatekeypassword,
"ListenUDP", CONF_STR, &options.listenudp,
"ListenTCP", CONF_STR, &options.listentcp,
"LogLevel", CONF_STR, &loglevel,
@@ -2166,10 +2237,12 @@ void getmainconfig(const char *configfile) {
"Client", CONF_CBK, confclsrv_cb,
"Server", CONF_CBK, confclsrv_cb,
"Realm", CONF_CBK, confrealm_cb,
+ "TLS", CONF_CBK, conftls_cb,
NULL
);
fclose(f);
-
+ tlsfree();
+
if (loglevel) {
if (strlen(loglevel) != 1 || *loglevel < '1' || *loglevel > '4')
debugx(1, DBG_ERR, "error in %s, value of option LogLevel is %s, must be 1, 2, 3 or 4", configfile, loglevel);
@@ -2259,9 +2332,6 @@ int main(int argc, char **argv) {
debugx(1, DBG_ERR, "pthread_create failed");
}
- if (client_tls_count || server_tls_count)
- ssl_ctx = ssl_init();
-
for (i = 0; i < server_count; i++)
if (pthread_create(&servers[i].clientth, NULL, clientwr, (void *)&servers[i]))
debugx(1, DBG_ERR, "pthread_create failed");
diff --git a/radsecproxy.conf-example b/radsecproxy.conf-example
index 7593b7c..029c7e1 100644
--- a/radsecproxy.conf-example
+++ b/radsecproxy.conf-example
@@ -1,17 +1,8 @@
#Master config file, must be in /etc/radsecproxy or proxy's current directory
# All possible config options are listed below
-#
-# You must specify at least one of TLSCACertificateFile or TLSCACertificatePath
-# for TLS to work. We always verify peer certificate (both client and server)
-#TLSCACertificateFile /etc/cacerts/CA.pem
-TLSCACertificatePath /etc/cacerts
-
-# You must specify the below for TLS, we will always present our certificate
-TLSCertificateFile /etc/hostcertkey/host.example.com.pem
-TLSCertificateKeyFile /etc/hostcertkey/host.example.com.key.pem
-# Optionally specify password if key is encrypted (not very secure)
-TLSCertificateKeyPassword "follow the white rabbit"
+# First you may define any global options, these are:
+#
# You can optionally specify addresses and ports to listen on
# Max one of each, below are just multiple examples
#ListenUDP *:1814
@@ -29,6 +20,34 @@ TLSCertificateKeyPassword "follow the white rabbit"
#LogDestination x-syslog://
#LogDestination x-syslog://log_local2
+#If we have TLS clients or servers we must define at least one tls block.
+#You can name them whatever you like and then reference them by name when
+#specifying clients or servers later. There are however three special names
+#"default", "defaultclient" and "defaultserver". If no name is defined for
+#a client, the "defaultclient" block will be used if it exists, if not the
+#"default" will be used. For a server, "defaultserver" followed by "default"
+#will be checked.
+#
+#The simplest configuration you can do is:
+tls default {
+ # You must specify at least one of CACertificateFile or CACertificatePath
+ # for TLS to work. We always verify peer certificate (client and server)
+ # CACertificateFile /etc/cacerts/CA.pem
+ CACertificatePath /etc/cacerts
+
+ # You must specify the below for TLS, we always present our certificate
+ CertificateFile /etc/hostcertkey/host.example.com.pem
+ CertificateKeyFile /etc/hostcertkey/host.example.com.key.pem
+ # Optionally specify password if key is encrypted (not very secure)
+ CertificateKeyPassword "follow the white rabbit"
+}
+
+#If you want one cert for all clients and another for all servers, use
+#defaultclient and defaultserver instead of default. If we wanted some
+#particular server to use something else you could specify a block
+#"tls myserver" and then reference that for that server. If you always
+#name the tls block in the client/server config you don't need a default
+
#Now we configure clients, servers and realms. Note that these and
#also the lines above may be in any order, except that a realm
#can only be configured to use a server that is previously configured.
@@ -45,6 +64,11 @@ TLSCertificateKeyPassword "follow the white rabbit"
client 2001:db8::1 {
type tls
secret verysecret
+#we could specify tls here, e.g.
+# tls myclient
+#in order to use tls parameters named myclient. We don't, so we will
+#use "tls defaultclient" if defined, or look for "tls default" as a
+#last resort
}
client 127.0.0.1 {
type udp
@@ -67,6 +91,11 @@ server 2001:db8::1 {
type TLS
port 2283
# secret is optional for TLS
+#we could specify tls here, e.g.
+# tls myserver
+#in order to use tls parameters named myserver. We don't, so we will
+#use "tls defaultserver" if defined, or look for "tls default" as a
+#last resort
}
server radius.example.com {
type tls
diff --git a/radsecproxy.h b/radsecproxy.h
index 1077496..6915b2a 100644
--- a/radsecproxy.h
+++ b/radsecproxy.h
@@ -44,11 +44,6 @@
#define CONF_CBK 2
struct options {
- char *tlscacertificatefile;
- char *tlscacertificatepath;
- char *tlscertificatefile;
- char *tlscertificatekeyfile;
- char *tlscertificatekeypassword;
char *listenudp;
char *listentcp;
char *logdestination;
@@ -87,6 +82,7 @@ struct peer {
char *port;
char *secret;
SSL *ssl;
+ SSL_CTX *ssl_ctx;
struct addrinfo *addrinfo;
};
@@ -117,6 +113,12 @@ struct realm {
struct server *server;
};
+struct tls {
+ char *name;
+ SSL_CTX *ctx;
+ int count;
+};
+
#define RADLEN(x) ntohs(((uint16_t *)(x))[1])
#define ATTRTYPE(x) ((x)[0])