Hi all, The patch that allows authorization decision in EAP-TLS module for freeRadius 1.1.6 is attached. This patch has the same functionality as previously announced patch for 1.1.0. The patch works as follows: after successful TLS authentication external script is invoked and subject name and issuer is passed to that script. So the script can decide if user is authorized. Cheers, Michal P. -- Michal Prochazka // michalp@ics.muni.cz Supercomputing Center Brno Institute of Computer Science Masaryk University Botanicka 68a, 60200 Brno, CZ CESNET z.s.p.o. Zikova 4, 16200 Praha 6, CZ Index: raddb/Makefile =================================================================== RCS file: /home/michalp/cvsroot/freeradius-tls/raddb/Makefile,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- raddb/Makefile 28 May 2007 07:17:06 -0000 1.1.1.1 +++ raddb/Makefile 28 May 2007 11:36:56 -0000 1.2 @@ -1,7 +1,7 @@ # # Makefile # -# Version: $Id: Makefile,v 1.1.1.1 2007/05/28 07:17:06 michalp Exp $ +# Version: $Id: Makefile,v 1.2 2007/05/28 11:36:56 michalp Exp $ # include ../Make.inc @@ -13,7 +13,7 @@ experimental.conf hints huntgroups ldap.attrmap \ mssql.conf naslist naspasswd oraclesql.conf postgresql.conf \ preproxy_users proxy.conf radiusd.conf realms snmp.conf \ - sql.conf sqlippool.conf users otp.conf + sql.conf sqlippool.conf users otp.conf check_tls_script all: Index: raddb/check_tls_script =================================================================== RCS file: raddb/check_tls_script diff -N raddb/check_tls_script --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ raddb/check_tls_script 28 May 2007 11:36:56 -0000 1.1 @@ -0,0 +1,27 @@ +#!/bin/sh + +# File containing subjects + issuers which are allowed +ALLOWED_CERTS_FILE=/etc/raddb/radius_allowed_certs +LOG_FILE=/var/log/radtls.log + +# Get values from env variables +SUBJECT=$X509_SUBJECT +ISSUER=$X509_ISSUER + + +# Get the number of occurrence of the ISSUER - SUBJECT in the +# ALLOWED_CERTS_FILE. +# This grep expression getting only exact match. +# !!! Keep in mind that issuer and subject is covered by double quotes !!! + +RESULT=`grep -x -c "$ISSUER - $SUBJECT" $ALLOWED_CERTS_FILE` + +# If one or more line matched log it else log unauthorize access +if [ $RESULT -ge 1 ]; then + echo -e `date` " $ISSUER - $SUBJECT - successfull" >> $LOG_FILE + exit 0 +else + echo -e `date` " $ISSUER - $SUBJECT - unatuhorized" >> $LOG_FILE + exit 1 +fi + Index: raddb/eap.conf =================================================================== RCS file: /home/michalp/cvsroot/freeradius-tls/raddb/eap.conf,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- raddb/eap.conf 28 May 2007 07:17:06 -0000 1.1.1.1 +++ raddb/eap.conf 28 May 2007 07:23:47 -0000 1.2 @@ -5,7 +5,7 @@ # common side effect of setting 'Auth-Type := EAP' is that the # users then cannot use ANY other authentication method. # -# $Id: eap.conf,v 1.1.1.1 2007/05/28 07:17:06 michalp Exp $ +# $Id: eap.conf,v 1.2 2007/05/28 07:23:47 michalp Exp $ # eap { # Invoke the default supported EAP type when @@ -189,7 +189,16 @@ # the check succeeds. # # check_cert_cn = %{User-Name} - # + + # Check the subject and issuer of the client certificate by + # the script. Script is invoked after successful TLS + # authentication. X509_SUBJECT and X509_ISSUER environ + # variables are passed to the script. Return value of the + # script decide if the request is discarded (return 0) or + # allowed (return != 0) + # + # check_script = /usr/local/etc/raddb/check_tls_script + # Set this option to specify the allowed # TLS cipher suites. The format is listed # in "man 1 ciphers". Index: share/dictionary.freeradius.internal =================================================================== RCS file: /home/michalp/cvsroot/freeradius-tls/share/dictionary.freeradius.internal,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- share/dictionary.freeradius.internal 28 May 2007 07:17:06 -0000 1.1.1.1 +++ share/dictionary.freeradius.internal 28 May 2007 07:23:47 -0000 1.2 @@ -2,7 +2,7 @@ # # Non Protocol Attributes used by FreeRADIUS # -# $Id: dictionary.freeradius.internal,v 1.1.1.1 2007/05/28 07:17:06 michalp Exp $ +# $Id: dictionary.freeradius.internal,v 1.2 2007/05/28 07:23:47 michalp Exp $ # # The attributes number ranges are allocates as follows: @@ -128,6 +128,8 @@ ATTRIBUTE Server-Identity 1099 string ATTRIBUTE Cleartext-Password 1100 string ATTRIBUTE Password-With-Header 1101 string +ATTRIBUTE X509-Subject 1102 string +ATTRIBUTE X509-Issuer 1103 string # # Range: 1200-1279 Index: src/include/radius.h =================================================================== RCS file: /home/michalp/cvsroot/freeradius-tls/src/include/radius.h,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- src/include/radius.h 28 May 2007 07:17:06 -0000 1.1.1.1 +++ src/include/radius.h 28 May 2007 07:23:47 -0000 1.2 @@ -1,7 +1,7 @@ /* * radius.h Constants of the radius protocol. * - * Version: $Id: radius.h,v 1.1.1.1 2007/05/28 07:17:06 michalp Exp $ + * Version: $Id: radius.h,v 1.2 2007/05/28 07:23:47 michalp Exp $ * */ @@ -201,7 +201,11 @@ #define PW_SMD5_PASSWORD 1096 #define PW_CLEARTEXT_PASSWORD 1100 #define PW_PASSWORD_WITH_HEADER 1101 - +/* +* X509 client Subject and Issuer +*/ +#define PW_X509_SUBJECT 1102 +#define PW_X509_ISSUER 1103 /* * Integer Translations Index: src/modules/rlm_eap/types/rlm_eap_tls/Makefile.in =================================================================== RCS file: /home/michalp/cvsroot/freeradius-tls/src/modules/rlm_eap/types/rlm_eap_tls/Makefile.in,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 Makefile.in --- src/modules/rlm_eap/types/rlm_eap_tls/Makefile.in 28 May 2007 07:17:06 -0000 1.1.1.1 +++ src/modules/rlm_eap/types/rlm_eap_tls/Makefile.in 28 May 2007 11:41:52 -0000 @@ -1,5 +1,5 @@ # -# $Id: Makefile.in,v 1.1.1.1 2007/05/28 07:17:06 michalp Exp $ +# $Id: Makefile.in,v 1.2 2007/05/28 07:23:47 michalp Exp $ # TARGET = @targetname@ @@ -7,7 +7,7 @@ HEADERS = rlm_eap_tls.h ../../eap.h ../../rlm_eap.h RLM_CFLAGS = -I../.. -I../../libeap $(INCLTDL) $(OPENSSL_INCLUDE) @eap_tls_cflags@ RLM_LIBS = @eap_tls_ldflags@ ../../libeap/libeap.la $(OPENSSL_LIBS) -RLM_INSTALL = +RLM_INSTALL = RLM_DIR=../../ include ${RLM_DIR}../rules.mak Index: src/modules/rlm_eap/types/rlm_eap_tls/check_tls_script.in =================================================================== RCS file: src/modules/rlm_eap/types/rlm_eap_tls/check_tls_script.in diff -N src/modules/rlm_eap/types/rlm_eap_tls/check_tls_script.in --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/modules/rlm_eap/types/rlm_eap_tls/check_tls_script.in 28 May 2007 08:05:34 -0000 1.1 @@ -0,0 +1,27 @@ +#!/bin/sh + +# File containing subjects + issuers which are allowed +ALLOWED_CERTS_FILE=@sysconfdir@/radius_allowed_certs +LOG_FILE=@logdir@/radtls.log + +# Get values from env variables +SUBJECT=$X509_SUBJECT +ISSUER=$X509_ISSUER + + +# Get the number of occurrence of the ISSUER - SUBJECT in the +# ALLOWED_CERTS_FILE. +# This grep expression getting only exact match. +# !!! Keep in mind that issuer and subject is covered by double quotes !!! + +RESULT=`grep -x -c "$ISSUER - $SUBJECT" $ALLOWED_CERTS_FILE` + +# If one or more line matched log it else log unauthorize access +if [ $RESULT -ge 1 ]; then + echo -e `date` " $ISSUER - $SUBJECT - successfull" >> $LOG_FILE + exit 0 +else + echo -e `date` " $ISSUER - $SUBJECT - unatuhorized" >> $LOG_FILE + exit 1 +fi + Index: src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c =================================================================== RCS file: /home/michalp/cvsroot/freeradius-tls/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c 28 May 2007 07:17:06 -0000 1.1.1.1 +++ src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c 28 May 2007 07:23:47 -0000 1.2 @@ -1,7 +1,7 @@ /* * rlm_eap_tls.c contains the interfaces that are called from eap * - * Version: $Id: rlm_eap_tls.c,v 1.1.1.1 2007/05/28 07:17:06 michalp Exp $ + * Version: $Id: rlm_eap_tls.c,v 1.2 2007/05/28 07:23:47 michalp Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -68,6 +68,8 @@ offsetof(EAP_TLS_CONF, cipher_list), NULL, NULL}, { "check_cert_issuer", PW_TYPE_STRING_PTR, offsetof(EAP_TLS_CONF, check_cert_issuer), NULL, NULL}, + { "check_script", PW_TYPE_STRING_PTR, + offsetof(EAP_TLS_CONF, check_script), NULL, NULL}, { NULL, -1, 0, NULL, NULL } /* end the list */ }; @@ -698,11 +700,14 @@ /* * Do authentication, by letting EAP-TLS do most of the work. */ -static int eaptls_authenticate(void *arg UNUSED, EAP_HANDLER *handler) +static int eaptls_authenticate(void *arg, EAP_HANDLER *handler) { eaptls_status_t status; tls_session_t *tls_session = (tls_session_t *) handler->opaque; - + eap_tls_t *inst; + + inst = (eap_tls_t *) arg; + DEBUG2(" rlm_eap_tls: Authenticate"); status = eaptls_process(handler); @@ -713,6 +718,71 @@ * EAP-TLS-Success packet here. */ case EAPTLS_SUCCESS: + /* + * When EAPTLS successed and if check_script is defined + * add X509 subject and issuer from client certificate + * to the packet and send it to the defined script by + * radius_exec_program. + */ + + + if (inst->conf->check_script != NULL) { + VALUE_PAIR *vp = NULL; + char x509_subject[256]; + char x509_issuer[256]; + int result; + + if (access(inst->conf->check_script, X_OK) != 0) { + DEBUG2(" eaptls_check_script: file %s not \ + found or it is not executable\n", + inst->conf->check_script); + return 0; + } + + DEBUG2(" eaptls_check_script: processing script %s\n", + inst->conf->check_script); + + + x509_subject[0] = x509_issuer[0] = '\0'; + X509_NAME_oneline(X509_get_subject_name(tls_session->ssl->session->peer), + x509_subject, 256); + X509_NAME_oneline(X509_get_issuer_name(tls_session->ssl->session->peer), + x509_issuer, 256); + + /* + * Create X509_Subject pair + */ + vp = paircreate(PW_X509_SUBJECT, PW_TYPE_OCTETS); + memcpy(vp->strvalue, x509_subject, strlen(x509_subject)); + vp->length = strlen(x509_subject); + pairadd(&(handler->request->packet->vps), vp); + vp = NULL; + + /* + * Create X509_Issuer pair + */ + vp = paircreate(PW_X509_ISSUER, PW_TYPE_OCTETS); + memcpy(vp->strvalue, x509_issuer, strlen(x509_issuer)); + vp->length = strlen(x509_issuer); + pairadd(&(handler->request->packet->vps), vp); + vp = NULL; + + /* + * Run the script and get the result of the script + */ + result = radius_exec_program( inst->conf->check_script, handler->request, + 1, NULL, 0, handler->request->packet->vps, NULL); + if (result != 0) { + radlog(L_ERR, " eaptls_check_script: rlm_exec (%s): \ + External script failed", + inst->conf->check_script); + return 0; + } + + pairdelete(&(handler->request->packet->vps), PW_X509_SUBJECT); + pairdelete(&(handler->request->packet->vps), PW_X509_ISSUER); + } + break; /* @@ -722,7 +792,6 @@ */ case EAPTLS_HANDLED: return 1; - /* * Handshake is done, proceed with decoding tunneled * data. Index: src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h =================================================================== RCS file: /home/michalp/cvsroot/freeradius-tls/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h 28 May 2007 07:17:06 -0000 1.1.1.1 +++ src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h 28 May 2007 07:23:47 -0000 1.2 @@ -1,7 +1,7 @@ /* * rlm_eap_tls.h * - * Version: $Id: rlm_eap_tls.h,v 1.1.1.1 2007/05/28 07:17:06 michalp Exp $ + * Version: $Id: rlm_eap_tls.h,v 1.2 2007/05/28 07:23:47 michalp Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,6 +54,7 @@ char *check_cert_cn; char *cipher_list; char *check_cert_issuer; + char *check_script; } EAP_TLS_CONF; /* This structure gets stored in arg */