From: Matthew Newton Date: Wed, 8 Feb 2012 10:51:44 +0000 (+0100) Subject: Add virtual-server option for EAP-TLS to allow certificate field checks X-Git-Tag: release_3_0_0_beta0~326 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=78725f40b7b960f77754fcd74c45af524706ca7d;p=thirdparty%2Ffreeradius-server.git Add virtual-server option for EAP-TLS to allow certificate field checks Normally attributes such as TLS-Client-Cert-Common-Name can be seen in Post-Auth only, which is too late to act if the return to the client should be changed. This code adds a virtual-server option to EAP-TLS to allow these values to be examined, and the return status updated accordingly. --- diff --git a/raddb/mods-available/eap b/raddb/mods-available/eap index 26a7f43ad8a..6bb736c18c1 100644 --- a/raddb/mods-available/eap +++ b/raddb/mods-available/eap @@ -308,6 +308,14 @@ # ecdh_curve = "prime256v1" + # + # As part of checking a client certificate, the EAP-TLS + # sets some attributes such as TLS-Client-Cert-CN. This + # virtual server has access to these attributes, and can + # be used to accept or reject the request. + # + # virtual_server = check-eap-tls + # # Session resumption / fast reauthentication # cache. diff --git a/raddb/sites-available/check-eap-tls b/raddb/sites-available/check-eap-tls new file mode 100644 index 00000000000..15dc628d8fd --- /dev/null +++ b/raddb/sites-available/check-eap-tls @@ -0,0 +1,54 @@ +# This virtual server allows EAP-TLS to reject access requests +# based on some certificate attributes. + +# Value-pairs that are available for checking include: +# +# TLS-Client-Cert-Subject +# TLS-Client-Cert-Issuer +# TLS-Client-Cert-Common-Name +# TLS-Client-Cert-Subject-Alt-Name-Email +# +# To see a full list of attributes, run the server in debug mode +# with this virtual server configured, and look at the attributes +# passed in to this virtual server. + +server check-eap-tls { + + +# Authorize - this is the only section required. +# +# To accept the access request, set Auth-Type = Accept, otherwise +# set it to Reject. + +authorize { + if ("%{TLS-Client-Cert-Common-Name}" == "client.example.com") { + update config { + Auth-Type = Accept + } + } + else { + update config { + Auth-Type = Reject + } + update reply { + Reply-Message = "Your certificate is not valid." + } + } + +# if ("host/%{TLS-Client-Cert-Common-Name}" == "%{User-Name}") { +# update config { +# Auth-Type = Accept +# } +# } +# else { +# update config { +# Auth-Type = Reject +# } +# } + +} + + + +} + diff --git a/src/include/tls.h b/src/include/tls.h index ffac65ff2df..2d78709a62a 100644 --- a/src/include/tls.h +++ b/src/include/tls.h @@ -367,6 +367,8 @@ struct fr_tls_server_conf_t { char *verify_client_cert_cmd; int require_client_cert; + char *virtual_server; /* for processing certificates */ + #ifdef HAVE_OPENSSL_OCSP_H /* * OCSP Configuration diff --git a/src/main/tls.c b/src/main/tls.c index 17332391746..cf29dd10549 100644 --- a/src/main/tls.c +++ b/src/main/tls.c @@ -831,6 +831,8 @@ static CONF_PARSER tls_server_config[] = { offsetof(fr_tls_server_conf_t, make_cert_command), NULL, NULL}, { "require_client_cert", PW_TYPE_BOOLEAN, offsetof(fr_tls_server_conf_t, require_client_cert), NULL, NULL }, + { "virtual_server", PW_TYPE_STRING_PTR, + offsetof(fr_tls_server_conf_t, virtual_server), NULL, NULL}, #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #ifndef OPENSSL_NO_ECDH diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c index 56ac6452420..6ec6267a428 100644 --- a/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c +++ b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c @@ -259,6 +259,7 @@ static int eaptls_authenticate(UNUSED void *arg, EAP_HANDLER *handler) fr_tls_status_t status; tls_session_t *tls_session = (tls_session_t *) handler->opaque; REQUEST *request = handler->request; + fr_tls_server_conf_t *conf; RDEBUG2("Authenticate"); @@ -268,8 +269,54 @@ static int eaptls_authenticate(UNUSED void *arg, EAP_HANDLER *handler) /* * EAP-TLS handshake was successful, return an * EAP-TLS-Success packet here. + * + * If a virtual server was configured, check that + * it accepts the certificates, too. */ case FR_TLS_SUCCESS: + conf = SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_CONF); + if (conf && conf->virtual_server) { + VALUE_PAIR *vp; + REQUEST *fake; + + /* create a fake request */ + fake = request_alloc_fake(request); + rad_assert(fake->packet->vps == NULL); + + fake->packet->vps = paircopy(request->packet->vps); + + /* set the virtual server to use */ + if ((vp = pairfind(request->config_items, + PW_VIRTUAL_SERVER, 0)) != NULL) { + fake->server = vp->vp_strvalue; + } else { + fake->server = conf->virtual_server; + } + + RDEBUG("Processing EAP-TLS Certificate check:"); + debug_pair_list(fake->packet->vps); + + RDEBUG("server %s {", fake->server); + + rad_authenticate(fake); + + RDEBUG("} # server %s", fake->server); + + /* copy the reply vps back to our reply */ + pairadd(&request->reply->vps, fake->reply->vps); + fake->reply->vps = NULL; + + /* reject if virtual server didn't return accept */ + if (fake->reply->code != PW_AUTHENTICATION_ACK) { + RDEBUG2("Certifictes were rejected by the virtual server"); + request_free(&fake); + eaptls_fail(handler, 0); + return 0; + } + + request_free(&fake); + /* success */ + } break; /*