From: Alan T. DeKok Date: Wed, 18 Aug 2010 15:42:30 +0000 (+0200) Subject: Added support for TLS-Cert-* and TLS-Client-Cert-* attributes X-Git-Tag: release_3_0_0_beta0~1295 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=freeradius.git;a=commitdiff_plain;h=b5b85ef0c0888cb262601eafefa0425bfb1deaa6 Added support for TLS-Cert-* and TLS-Client-Cert-* attributes This has been needed for a long time. They only work for methods which use a client certificate, but it's a start. --- diff --git a/raddb/sites-available/default b/raddb/sites-available/default index a8b6cd9..783cd5e 100644 --- a/raddb/sites-available/default +++ b/raddb/sites-available/default @@ -497,6 +497,31 @@ post-auth { # # wimax + # If there is a client certificate (EAP-TLS, sometimes PEAP + # and TTLS), then some attributes are filled out after the + # certificate verification has been performed. These fields + # MAY be available during the authentication, or they may be + # available only in the "post-auth" section. + # + # The first set of attributes contains information about the + # CA which is being used. The second contains information + # about the client certificate (if available). +# +# update reply { +# Reply-Message += "%{TLS-Cert-Serial}" +# Reply-Message += "%{TLS-Cert-Expiration}" +# Reply-Message += "%{TLS-Cert-Subject}" +# Reply-Message += "%{TLS-Cert-Issuer}" +# Reply-Message += "%{TLS-Cert-Common-Name}" +# +# Reply-Message += "%{TLS-Client-Cert-Serial}" +# Reply-Message += "%{TLS-Client-Cert-Expiration}" +# Reply-Message += "%{TLS-Client-Cert-Subject}" +# Reply-Message += "%{TLS-Client-Cert-Issuer}" +# Reply-Message += "%{TLS-Client-Cert-Common-Name}" +#x } + + # If the WiMAX module did it's work, you may want to do more # things here, like delete the MS-MPPE-*-Key attributes. # diff --git a/share/dictionary.freeradius.internal b/share/dictionary.freeradius.internal index b0b168e..b7022e8 100644 --- a/share/dictionary.freeradius.internal +++ b/share/dictionary.freeradius.internal @@ -344,6 +344,18 @@ ATTRIBUTE WiMAX-MN-NAI 1900 string ATTRIBUTE WiMAX-FA-IP-Address 1901 ipaddr ATTRIBUTE WiMAX-MN-FA 1902 octets +ATTRIBUTE TLS-Cert-Serial 1910 string +ATTRIBUTE TLS-Cert-Expiration 1911 string +ATTRIBUTE TLS-Cert-Issuer 1912 string +ATTRIBUTE TLS-Cert-Subject 1913 string +ATTRIBUTE TLS-Cert-Common-Name 1914 string +# 1915 - 1919: reserved for future cert attributes +ATTRIBUTE TLS-Client-Cert-Serial 1920 string +ATTRIBUTE TLS-Client-Cert-Expiration 1921 string +ATTRIBUTE TLS-Client-Cert-Issuer 1922 string +ATTRIBUTE TLS-Client-Cert-Subject 1923 string +ATTRIBUTE TLS-Client-Cert-Common-Name 1924 string + # # Range: 1910-2999 # Free diff --git a/src/modules/rlm_eap/eap.h b/src/modules/rlm_eap/eap.h index b8774d6..0150ef2 100644 --- a/src/modules/rlm_eap/eap.h +++ b/src/modules/rlm_eap/eap.h @@ -116,6 +116,7 @@ typedef struct _eap_handler { int tls; int finished; + VALUE_PAIR *certs; } EAP_HANDLER; /* diff --git a/src/modules/rlm_eap/libeap/eap_tls.c b/src/modules/rlm_eap/libeap/eap_tls.c index 2c39c66..1c15db1 100644 --- a/src/modules/rlm_eap/libeap/eap_tls.c +++ b/src/modules/rlm_eap/libeap/eap_tls.c @@ -840,6 +840,8 @@ eaptls_status_t eaptls_process(EAP_HANDLER *handler) REQUEST *request = handler->request; RDEBUG2("processing EAP-TLS"); + if (handler->certs) pairadd(&request->packet->vps, + paircopy(handler->certs)); /* This case is when SSL generates Alert then we * send that alert to the client and then send the EAP-Failure diff --git a/src/modules/rlm_eap/mem.c b/src/modules/rlm_eap/mem.c index f782d2f..5bdf633 100644 --- a/src/modules/rlm_eap/mem.c +++ b/src/modules/rlm_eap/mem.c @@ -157,6 +157,8 @@ void eap_handler_free(rlm_eap_t *inst, EAP_HANDLER *handler) handler->opaque = NULL; handler->free_opaque = NULL; + if (handler->certs) pairfree(&handler->certs); + free(handler); } 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 5b624ee..1ae5292 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 @@ -214,6 +214,18 @@ static SSL_SESSION *cbtls_get_session(UNUSED SSL *s, } /* + * For creating certificate attributes. + */ +static const char *cert_attr_names[5][2] = { + { "TLS-Client-Cert-Serial", "TLS-Cert-Serial" }, + { "TLS-Client-Cert-Expiration", "TLS-Cert-Expiraton" }, + { "TLS-Client-Cert-Issuer", "TLS-Cert-Issuer" }, + { "TLS-Client-Cert-Subject", "TLS-Cert-Subject" }, + { "TLS-Client-Cert-Common-Name", "TLS-Cert-Common-Name" } +}; + + +/* * Before trusting a certificate, you must make sure that the * certificate is 'valid'. There are several steps that your * application can take in determining if a certificate is @@ -244,23 +256,23 @@ static int cbtls_verify(int ok, X509_STORE_CTX *ctx) char issuer[1024]; /* Used for the issuer name */ char common_name[1024]; char cn_str[1024]; + char buf[64]; EAP_HANDLER *handler = NULL; X509 *client_cert; SSL *ssl; - int err, depth; + int err, depth, lookup; EAP_TLS_CONF *conf; int my_ok = ok; REQUEST *request; + ASN1_INTEGER *sn = NULL; + ASN1_TIME *asn_time = NULL; client_cert = X509_STORE_CTX_get_current_cert(ctx); err = X509_STORE_CTX_get_error(ctx); depth = X509_STORE_CTX_get_error_depth(ctx); - if (!my_ok) { - radlog(L_ERR,"--> verify error:num=%d:%s\n",err, - X509_verify_cert_error_string(err)); - return my_ok; - } + lookup = depth; + if (lookup > 1) lookup = 1; /* * Retrieve the pointer to the SSL of the connection currently treated @@ -272,16 +284,54 @@ static int cbtls_verify(int ok, X509_STORE_CTX *ctx) conf = (EAP_TLS_CONF *)SSL_get_ex_data(ssl, 1); /* + * Get the Serial Number + */ + buf[0] = '\0'; + sn = X509_get_serialNumber(client_cert); + if (sn && (sn->length < (sizeof(buf) / 2))) { + char *p = buf; + int i; + + for (i = 0; i < sn->length; i++) { + sprintf(buf, "%02x", (unsigned int)sn->data[i]); + p += 2; + } + pairadd(&handler->certs, + pairmake(cert_attr_names[0][lookup], buf, T_OP_SET)); + } + + + /* + * Get the Expiration Date + */ + buf[0] = '\0'; + asn_time = X509_get_notAfter(client_cert); + if (asn_time && (asn_time->length < MAX_STRING_LEN)) { + memcpy(buf, (char*) asn_time->data, asn_time->length); + buf[asn_time->length] = '\0'; + pairadd(&handler->certs, + pairmake(cert_attr_names[1][lookup], buf, T_OP_SET)); + } + + /* * Get the Subject & Issuer */ subject[0] = issuer[0] = '\0'; X509_NAME_oneline(X509_get_subject_name(client_cert), subject, sizeof(subject)); + subject[sizeof(subject) - 1] = '\0'; + if (subject[0] && (strlen(subject) < MAX_STRING_LEN)) { + pairadd(&handler->certs, + pairmake(cert_attr_names[2][lookup], subject, T_OP_SET)); + } + X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), issuer, sizeof(issuer)); - - subject[sizeof(subject) - 1] = '\0'; issuer[sizeof(issuer) - 1] = '\0'; + if (issuer[0] && (strlen(issuer) < MAX_STRING_LEN)) { + pairadd(&handler->certs, + pairmake(cert_attr_names[3][lookup], issuer, T_OP_SET)); + } /* * Get the Common Name @@ -289,6 +339,18 @@ static int cbtls_verify(int ok, X509_STORE_CTX *ctx) X509_NAME_get_text_by_NID(X509_get_subject_name(client_cert), NID_commonName, common_name, sizeof(common_name)); common_name[sizeof(common_name) - 1] = '\0'; + if (common_name[0] && (strlen(common_name) < MAX_STRING_LEN)) { + pairadd(&handler->certs, + pairmake(cert_attr_names[4][lookup], common_name, T_OP_SET)); + } + + if (!my_ok) { + const char *p = X509_verify_cert_error_string(err); + radlog(L_ERR,"--> verify error:num=%d:%s\n",err, p); + radius_pairmake(request, &request->packet->vps, + "Module-Failure-Message", p, T_OP_SET); + return my_ok; + } switch (ctx->error) { diff --git a/src/tests/eap-tls.conf b/src/tests/eap-tls.conf new file mode 100644 index 0000000..0d1b31e --- /dev/null +++ b/src/tests/eap-tls.conf @@ -0,0 +1,15 @@ +# +# eapol_test -c eap-tls.conf -s testing123 +# +# Set also "nostrip" in raddb/proxy.conf, realm "example.com" +# And make it a LOCAL realm. +# +network={ + key_mgmt=WPA-EAP + eap=TLS + identity="user@example.com" + ca_cert="../../raddb/certs/ca.pem" + client_cert="../../raddb/certs/client.crt" + private_key="../../raddb/certs/client.key" + private_key_passwd="whatever" +}