Commit ecf7685a authored by venaas's avatar venaas Committed by venaas

completely changed TLS configuration

git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@118 e88ac4ed-0b26-0410-9574-a7f39faa03bf
parent 305e2f3e
......@@ -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");
......
#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
......
......@@ -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])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment