From cff9dae64ddb2ead188889c9164961bd364e8cd2 Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Mon, 20 Sep 2010 19:39:39 +0200 Subject: [PATCH] Support for libradius --- Makefile.am | 4 +- accept_sec_context.c | 392 ++++++++++++++------------------------------------- gssapiP_eap.h | 20 ++- init_sec_context.c | 4 +- util_context.c | 9 +- util_name.c | 21 ++- 6 files changed, 139 insertions(+), 311 deletions(-) diff --git a/Makefile.am b/Makefile.am index 336354a..aa22204 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,7 @@ gssdir = $(libdir)/gss gss_LTLIBRARIES = libmech_eap.la -libmech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB +libmech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\" libmech_eap_la_CFLAGS = -g -Wall -fno-strict-aliasing \ @EAP_CFLAGS@ @KRB5_CFLAGS@ @TARGET_CFLAGS@ libmech_eap_la_CXXFLAGS = -g -Wall \ @@ -13,7 +13,7 @@ libmech_eap_la_CXXFLAGS = -g -Wall \ libmech_eap_la_LDFLAGS = -export-symbols mech_eap.exports -version-info 0:0:0 \ -no-undefined \ @EAP_LDFLAGS@ @KRB5_LDFLAGS@ @TARGET_LDFLAGS@ -libmech_eap_la_LIBADD = @EAP_LIBS@ @KRB5_LIBS@ @SHIBSP_LIBS@ @SHIBRESOLVER_LIBS@ +libmech_eap_la_LIBADD = @EAP_LIBS@ @KRB5_LIBS@ @SHIBSP_LIBS@ @SHIBRESOLVER_LIBS@ -lfreeradius-client libmech_eap_la_SOURCES = \ accept_sec_context.c \ diff --git a/accept_sec_context.c b/accept_sec_context.c index 6353eea..d54fb2a 100644 --- a/accept_sec_context.c +++ b/accept_sec_context.c @@ -32,203 +32,69 @@ #include "gssapiP_eap.h" -#ifdef BUILTIN_EAP -#define EAP_KEY_AVAILABLE(ctx) ((ctx)->acceptorCtx.eapPolInterface->eapKeyAvailable) -#define EAP_KEY_DATA(ctx) ((ctx)->acceptorCtx.eapPolInterface->eapKeyData) -#define EAP_KEY_LENGTH(ctx) ((ctx)->acceptorCtx.eapPolInterface->eapKeyDataLen) -#else -#define EAP_KEY_AVAILABLE(ctx) 0 -#define EAP_KEY_DATA(ctx) NULL -#define EAP_KEY_LENGTH(ctx) 0 -#endif /* BUILTIN_EAP */ - -static OM_uint32 -acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx); - -#ifdef BUILTIN_EAP -#define EAP_MAX_METHODS 8 - -#define EAP_TTLS_AUTH_PAP 1 -#define EAP_TTLS_AUTH_CHAP 2 -#define EAP_TTLS_AUTH_MSCHAP 4 -#define EAP_TTLS_AUTH_MSCHAPV2 8 - -struct eap_user { - struct { - int vendor; - u32 method; - } methods[EAP_MAX_METHODS]; - u8 *password; - size_t password_len; - int password_hash; /* whether password is hashed with - * nt_password_hash() */ - int phase2; - int force_version; - int ttls_auth; /* bitfield of - * EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */ -}; - -struct eap_eapol_interface { - /* Lower layer to full authenticator variables */ - Boolean eapResp; /* shared with EAPOL Backend Authentication */ - struct wpabuf *eapRespData; - Boolean portEnabled; - int retransWhile; - Boolean eapRestart; /* shared with EAPOL Authenticator PAE */ - int eapSRTT; - int eapRTTVAR; - - /* Full authenticator to lower layer variables */ - Boolean eapReq; /* shared with EAPOL Backend Authentication */ - Boolean eapNoReq; /* shared with EAPOL Backend Authentication */ - Boolean eapSuccess; - Boolean eapFail; - Boolean eapTimeout; - struct wpabuf *eapReqData; - u8 *eapKeyData; - size_t eapKeyDataLen; - Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */ - - /* AAA interface to full authenticator variables */ - Boolean aaaEapReq; - Boolean aaaEapNoReq; - Boolean aaaSuccess; - Boolean aaaFail; - struct wpabuf *aaaEapReqData; - u8 *aaaEapKeyData; - size_t aaaEapKeyDataLen; - Boolean aaaEapKeyAvailable; - int aaaMethodTimeout; - - /* Full authenticator to AAA interface variables */ - Boolean aaaEapResp; - struct wpabuf *aaaEapRespData; - /* aaaIdentity -> eap_get_identity() */ - Boolean aaaTimeout; -}; - -#define eapol_callbacks SERVER_eapol_callbacks - -struct eapol_callbacks { - int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, - int phase2, struct eap_user *user); - const char * (*get_eap_req_id_text)(void *ctx, size_t *len); -}; - -#define eap_config SERVER_eap_config - -struct eap_config { - void *ssl_ctx; - void *msg_ctx; - void *eap_sim_db_priv; - Boolean backend_auth; - int eap_server; - u8 *pac_opaque_encr_key; - u8 *eap_fast_a_id; - size_t eap_fast_a_id_len; - char *eap_fast_a_id_info; - int eap_fast_prov; - int pac_key_lifetime; - int pac_key_refresh_time; - int eap_sim_aka_result_ind; - int tnc; - struct wps_context *wps; - const struct wpabuf *assoc_wps_ie; - const u8 *peer_addr; - int fragment_size; -}; - -struct eap_sm * eap_server_sm_init(void *eapol_ctx, - struct eapol_callbacks *eapol_cb, - struct eap_config *eap_conf); -void eap_server_sm_deinit(struct eap_sm *sm); -int eap_server_sm_step(struct eap_sm *sm); -void eap_sm_notify_cached(struct eap_sm *sm); -void eap_sm_pending_cb(struct eap_sm *sm); -int eap_sm_method_pending(struct eap_sm *sm); -const u8 * eap_get_identity(struct eap_sm *sm, size_t *len); -struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm); - -#include +#define RC_CONFIG_FILE SYSCONFDIR "/radiusclient/radiusclient.conf" +/* + * Mark a context as ready for cryptographic operations + */ static OM_uint32 -initTls(OM_uint32 *minor, - gss_ctx_id_t ctx) +acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx) { - struct tls_config tconf; - struct tls_connection_params tparams; - - memset(&tconf, 0, sizeof(tconf)); - ctx->acceptorCtx.tlsContext = tls_init(&tconf); - if (ctx->acceptorCtx.tlsContext == NULL) - return GSS_S_FAILURE; - - memset(&tparams, 0, sizeof(tparams)); - tparams.ca_cert = "ca.pem"; - tparams.client_cert = "server.pem"; - tparams.private_key = "server-key.pem"; + OM_uint32 major; + VALUE_PAIR *vp; + gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; - if (tls_global_set_params(ctx->acceptorCtx.tlsContext, &tparams)) { - return GSS_S_FAILURE; - } + /* Cache encryption type derived from selected mechanism OID */ + major = gssEapOidToEnctype(minor, ctx->mechanismUsed, + &ctx->encryptionType); + if (GSS_ERROR(major)) + return major; - if (tls_global_set_verify(ctx->acceptorCtx.tlsContext, 0)) { - return GSS_S_FAILURE; + vp = rc_avpair_get(ctx->acceptorCtx.avps, PW_USER_NAME, 0); + if (vp != NULL) { + nameBuf.length = vp->lvalue; + nameBuf.value = vp->strvalue; + } else { + ctx->gssFlags |= GSS_C_ANON_FLAG; } - return GSS_S_COMPLETE; -} - -static int -serverGetEapUser(void *ctx, - const unsigned char *identity, - size_t identityLength, - int phase2, - struct eap_user *user) -{ - gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx; - OM_uint32 major, minor; - gss_buffer_desc buf; - - memset(user, 0, sizeof(*user)); + major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME, + &ctx->initiatorName); + if (GSS_ERROR(major)) + return major; - buf.length = identityLength; - buf.value = (void *)identity; + vp = rc_avpair_get(ctx->acceptorCtx.avps, PW_MSCHAP2_SUCCESS, 0); + if (ctx->encryptionType != ENCTYPE_NULL && vp != NULL) { + major = gssEapDeriveRfc3961Key(minor, + (unsigned char *)vp->strvalue, + vp->lvalue, + ctx->encryptionType, + &ctx->rfc3961Key); + if (GSS_ERROR(major)) + return major; - if (phase2 == 0) { - user->methods[0].vendor = EAP_VENDOR_IETF; - user->methods[0].method = EAP_TYPE_PEAP; - return 0; + major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key, + &ctx->checksumType); + if (GSS_ERROR(major)) + return major; + } else { + /* + * draft-howlett-eap-gss says that integrity/confidentialty should + * always be advertised as available, but if we have no keying + * material it seems confusing to the caller to advertise this. + */ + ctx->gssFlags &= ~(GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); } - major = gssEapImportName(&minor, &buf, GSS_C_NT_USER_NAME, - &gssCtx->initiatorName); + major = sequenceInit(minor, + &ctx->seqState, ctx->recvSeq, + ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0), + ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0), + TRUE); if (GSS_ERROR(major)) - return -1; - - /* - * OK, obviously there is no real security here, this is simply - * for testing the token exchange; this code will be completely - * replaced with libradius once that library is available. - */ - user->methods[0].vendor = EAP_VENDOR_IETF; - user->methods[0].method = EAP_TYPE_MSCHAPV2; - user->password = (unsigned char *)strdup(" "); - user->password_len = 1; - - gssCtx->initiatorName->attrCtx = gssEapCreateAttrContext(NULL, gssCtx); - if (gssCtx->initiatorName->attrCtx != NULL) - gssCtx->initiatorName->flags |= NAME_FLAG_COMPOSITE; - - return 0; -} + return major; -static const char * -serverGetEapReqIdText(void *ctx, - size_t *len) -{ - *len = 0; - return NULL; + return GSS_S_COMPLETE; } static OM_uint32 @@ -240,30 +106,26 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, gss_buffer_t outputToken) { OM_uint32 major; - OM_uint32 tmpMinor, tmpMajor; + OM_uint32 service = PW_AUTHENTICATE_ONLY; int code; - struct wpabuf respData; - static struct eapol_callbacks cb = { serverGetEapUser, serverGetEapReqIdText }; - if (ctx->acceptorCtx.eap == NULL) { - struct eap_config eapConfig; - - major = initTls(minor, ctx); - if (GSS_ERROR(major)) + VALUE_PAIR *send = NULL; + VALUE_PAIR *received = NULL; + rc_handle *rh = ctx->acceptorCtx.radHandle; + char msgBuffer[4096]; + + if (rh == NULL) { + rh = ctx->acceptorCtx.radHandle = rc_read_config(RC_CONFIG_FILE); + if (rh == NULL) { + *minor = errno; + major = GSS_S_FAILURE; goto cleanup; + } - memset(&eapConfig, 0, sizeof(eapConfig)); - eapConfig.eap_server = 1; - eapConfig.ssl_ctx = ctx->acceptorCtx.tlsContext; - - ctx->acceptorCtx.eap = eap_server_sm_init(ctx, &cb, &eapConfig); - if (ctx->acceptorCtx.eap == NULL) { + if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) { + *minor = errno; major = GSS_S_FAILURE; goto cleanup; } - - ctx->acceptorCtx.eapPolInterface = eap_get_interface(ctx->acceptorCtx.eap); - ctx->acceptorCtx.eapPolInterface->portEnabled = TRUE; - ctx->acceptorCtx.eapPolInterface->eapRestart = TRUE; } if (ctx->acceptorName == GSS_C_NO_NAME && @@ -274,66 +136,64 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, goto cleanup; } - wpabuf_set(&respData, inputToken->value, inputToken->length); - ctx->acceptorCtx.eapPolInterface->eapRespData = &respData; - ctx->acceptorCtx.eapPolInterface->eapResp = TRUE; + if (rc_avpair_add(rh, &send, PW_EAP_MESSAGE, + inputToken->value, inputToken->length, 0) == NULL) { + *minor = ENOMEM; + major = GSS_S_FAILURE; + goto cleanup; + } - code = eap_server_sm_step(ctx->acceptorCtx.eap); + if (rc_avpair_add(rh, &send, PW_SERVICE_TYPE, &service, -1, 0) == NULL) { + *minor = ENOMEM; + major = GSS_S_FAILURE; + goto cleanup; + } - if (ctx->acceptorCtx.eapPolInterface->eapReq) { - ctx->acceptorCtx.eapPolInterface->eapReq = 0; - major = GSS_S_CONTINUE_NEEDED; + code = rc_auth(rh, 0, send, &received, msgBuffer); + if (code != 0) { + *minor = errno; + major = GSS_S_UNAVAILABLE; + goto cleanup; } - if (ctx->acceptorCtx.eapPolInterface->eapSuccess) { - ctx->acceptorCtx.eapPolInterface->eapSuccess = 0; - major = acceptReady(minor, ctx); + if (code == OK_RC || code == PW_ACCESS_CHALLENGE) { + VALUE_PAIR *eapResponse; + gss_buffer_desc eapBuf = GSS_C_EMPTY_BUFFER; + + eapResponse = rc_avpair_get(received, PW_EAP_MESSAGE, 0); + if (eapResponse != NULL) { + eapBuf.length = eapResponse->lvalue; + eapBuf.value = eapResponse->strvalue; + } + + major = duplicateBuffer(minor, &eapBuf, outputToken); if (GSS_ERROR(major)) goto cleanup; - ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS; major = GSS_S_CONTINUE_NEEDED; - } else if (ctx->acceptorCtx.eapPolInterface->eapFail) { - ctx->acceptorCtx.eapPolInterface->eapFail = 0; - major = GSS_S_FAILURE; - } else if (code == 0) { + } else { major = GSS_S_FAILURE; + goto cleanup; } - if (ctx->acceptorCtx.eapPolInterface->eapReqData != NULL) { - gss_buffer_desc buf; + if (code == OK_RC) { + ctx->acceptorCtx.avps = received; + received = NULL; - buf.length = wpabuf_len(ctx->acceptorCtx.eapPolInterface->eapReqData); - buf.value = (void *)wpabuf_head(ctx->acceptorCtx.eapPolInterface->eapReqData); - - tmpMajor = duplicateBuffer(&tmpMinor, &buf, outputToken); - if (GSS_ERROR(tmpMajor)) { - major = tmpMajor; - *minor = tmpMinor; + major = acceptReady(minor, ctx); + if (GSS_ERROR(major)) goto cleanup; - } + + ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS; + major = GSS_S_CONTINUE_NEEDED; } cleanup: - ctx->acceptorCtx.eapPolInterface->eapRespData = NULL; - - return major; -} -#else -static OM_uint32 -eapGssSmAcceptAuthenticate(OM_uint32 *minor, - gss_ctx_id_t ctx, - gss_cred_id_t cred, - gss_buffer_t inputToken, - gss_channel_bindings_t chanBindings, - gss_buffer_t outputToken) -{ - OM_uint32 major, tmpMinor; + if (received != NULL) + rc_avpair_free(received); -cleanup: return major; } -#endif /* BUILTIN_EAP */ static OM_uint32 eapGssSmAcceptGssChannelBindings(OM_uint32 *minor, @@ -530,49 +390,3 @@ cleanup: return major; } -/* - * Mark a context as ready for cryptographic operations - */ -static OM_uint32 -acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx) -{ - OM_uint32 major; - - /* Cache encryption type derived from selected mechanism OID */ - major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType); - if (GSS_ERROR(major)) - return major; - - if (ctx->encryptionType != ENCTYPE_NULL && - EAP_KEY_AVAILABLE(ctx)) { - major = gssEapDeriveRfc3961Key(minor, - EAP_KEY_DATA(ctx), - EAP_KEY_LENGTH(ctx), - ctx->encryptionType, - &ctx->rfc3961Key); - if (GSS_ERROR(major)) - return major; - - major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key, - &ctx->checksumType); - if (GSS_ERROR(major)) - return major; - } else { - /* - * draft-howlett-eap-gss says that integrity/confidentialty should - * always be advertised as available, but if we have no keying - * material it seems confusing to the caller to advertise this. - */ - ctx->gssFlags &= ~(GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); - } - - major = sequenceInit(minor, - &ctx->seqState, ctx->recvSeq, - ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0), - ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0), - TRUE); - if (GSS_ERROR(major)) - return major; - - return GSS_S_COMPLETE; -} diff --git a/gssapiP_eap.h b/gssapiP_eap.h index bb61a01..eef4206 100644 --- a/gssapiP_eap.h +++ b/gssapiP_eap.h @@ -33,8 +33,6 @@ #ifndef _GSSAPIP_EAP_H_ #define _GSSAPIP_EAP_H_ 1 -#define BUILTIN_EAP 1 - #include #include #include @@ -60,6 +58,17 @@ #include #endif +#ifdef __cplusplus +struct rc_conf; +typedef struct rc_conf rc_handle; + +struct value_pair; +typedef struct value_pair VALUE_PAIR; +#else +#include +#include +#endif + /* These name flags are informative and not actually used by anything yet */ #define NAME_FLAG_NAI 0x00000001 #define NAME_FLAG_SERVICE 0x00000002 @@ -127,11 +136,8 @@ struct gss_eap_initiator_ctx { }; struct gss_eap_acceptor_ctx { -#if defined(BUILTIN_EAP) && !defined(__cplusplus) - struct eap_eapol_interface *eapPolInterface; - void *tlsContext; - struct eap_sm *eap; -#endif + rc_handle *radHandle; + VALUE_PAIR *avps; }; struct gss_ctx_id_struct { diff --git a/init_sec_context.c b/init_sec_context.c index 8b5a0e2..9ec5e66 100644 --- a/init_sec_context.c +++ b/init_sec_context.c @@ -375,7 +375,9 @@ eapGssSmInitAuthenticate(OM_uint32 *minor, ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS); major = GSS_S_CONTINUE_NEEDED; ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS; - } else if ((ctx->flags & CTX_FLAG_EAP_FAIL) || code == 0) { + } else if (ctx->flags & CTX_FLAG_EAP_FAIL) { + major = GSS_S_DEFECTIVE_CREDENTIAL; + } else if (code == 0) { major = GSS_S_FAILURE; } diff --git a/util_context.c b/util_context.c index 13372ea..99c9405 100644 --- a/util_context.c +++ b/util_context.c @@ -82,11 +82,10 @@ releaseInitiatorContext(struct gss_eap_initiator_ctx *ctx) static void releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx) { -#ifdef BUILTIN_EAP - eap_server_sm_deinit(ctx->eap); - if (ctx->tlsContext != NULL) - tls_deinit(ctx->tlsContext); -#endif + if (ctx->avps != NULL) + rc_avpair_free(ctx->avps); + if (ctx->radHandle != NULL) + rc_config_free(ctx->radHandle); } OM_uint32 diff --git a/util_name.c b/util_name.c index d45b60f..e64ebdd 100644 --- a/util_name.c +++ b/util_name.c @@ -194,14 +194,21 @@ importUserName(OM_uint32 *minor, GSSEAP_KRB_INIT(&krbContext); - major = bufferToString(minor, nameBuffer, &nameString); - if (GSS_ERROR(major)) - return major; + if (nameBuffer == GSS_C_NO_BUFFER) { + *minor = krb5_copy_principal(krbContext, + krb5_anonymous_principal(), &krbPrinc); + if (*minor != 0) + return GSS_S_FAILURE; + } else { + major = bufferToString(minor, nameBuffer, &nameString); + if (GSS_ERROR(major)) + return major; - *minor = krb5_parse_name(krbContext, nameString, &krbPrinc); - if (*minor != 0) { - GSSEAP_FREE(nameString); - return GSS_S_FAILURE; + *minor = krb5_parse_name(krbContext, nameString, &krbPrinc); + if (*minor != 0) { + GSSEAP_FREE(nameString); + return GSS_S_FAILURE; + } } major = krbPrincipalToName(minor, &krbPrinc, pName); -- 2.1.4