EAP Channel binding support
authorSam Hartman <hartmans@debian.org>
Fri, 13 Sep 2013 19:41:19 +0000 (15:41 -0400)
committerSam Hartman <hartmans@debian.org>
Fri, 13 Sep 2013 19:41:19 +0000 (15:41 -0400)
Merge remote-tracking branch 'origin/eap-chbind'

Conflicts:
mech_eap/accept_sec_context.c
mech_eap/dictionary.ukerna
mech_eap/gsseap_err.et
mech_eap/util_radius.h

34 files changed:
.gitignore
configure.ac
libeap/src/utils/common.h
mech_eap.spec.in
mech_eap/README
mech_eap/README.samba4
mech_eap/TODO
mech_eap/accept_sec_context.c
mech_eap/compare_name.c
mech_eap/dictionary.ukerna
mech_eap/export_sec_context.c
mech_eap/gssapiP_eap.h
mech_eap/gsseap_err.et
mech_eap/import_sec_context.c
mech_eap/init_sec_context.c
mech_eap/inquire_context.c
mech_eap/inquire_sec_context_by_oid.c
mech_eap/mech
mech_eap/pseudo_random.c
mech_eap/radsec.conf
mech_eap/util.h
mech_eap/util_adshim.c
mech_eap/util_context.c
mech_eap/util_cred.c
mech_eap/util_krb.c
mech_eap/util_mech.c
mech_eap/util_moonshot.c
mech_eap/util_name.c
mech_eap/util_ordering.c
mech_eap/util_radius.cpp
mech_eap/util_radius.h
mech_eap/util_reauth.c
mech_eap/util_saml.cpp
mech_eap/util_shib.cpp

index 57a94cd..3674727 100644 (file)
@@ -12,3 +12,5 @@ build-aux
 !build-aux/compile
 mech_eap.spec
 mech_eap*tar*
+*.lo
+*#
index 4297345..469be5e 100644 (file)
@@ -1,5 +1,5 @@
-AC_PREREQ([2.61])
-AC_INIT([mech_eap], [0.1], [bugs@project-moonshot.org])
+/AC_PREREQ([2.61])
+AC_INIT([mech_eap], [0.9], [bugs@project-moonshot.org])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_AUX_DIR([build-aux])
 
index 79a394e..2868df7 100644 (file)
@@ -92,7 +92,9 @@ typedef int socklen_t;
 #endif /* CONFIG_NATIVE_WINDOWS */
 
 #ifdef _MSC_VER
+#ifndef __cplusplus
 #define inline __inline
+#endif
 
 #undef vsnprintf
 #define vsnprintf _vsnprintf
index ada2f90..83984c6 100644 (file)
@@ -1,7 +1,7 @@
 %global _moonshot_krb5 %{!?_moonshot_krb5:krb5-devel}%{?_moonshot_krb5}
 Name:          moonshot-gss-eap
 Version:       @VERSION@
-Release:       4%{?dist}
+Release:       3%{?dist}
 Summary:       Moonshot GSS-API Mechanism
 
 Group:         Security Tools
@@ -14,8 +14,8 @@ BuildRequires:         %{_moonshot_krb5} >= 1.9.1
 BuildRequires:  moonshot-ui-devel
 BuildRequires: jansson-devel
 Requires:      moonshot-ui
-BuildRequires: libradsec-devel
-BuildRequires: shibboleth-devel >= 2.5
+BuildRequires: libradsec-devel >= 0.0.3
+BuildRequires: shibboleth-sp-devel >= 2.5
 BuildRequires: libshibresolver-devel
 
 
@@ -29,8 +29,7 @@ Project Moonshot provides federated access management.
 
 
 %build
-       export LDFLAGS='-L/usr/%{_lib}/freeradius -Wl,--rpath=/usr/%{_lib}/freeradius'
-%configure  --with-libmoonshot=%{_prefix} --with-krb5=%{_prefix} --disable-reauth
+%configure  --with-libmoonshot=%{_prefix} --with-krb5=%{_prefix} --enable-reauth LDFLAGs="${LDFLAGS} -L/opt/shibboleth/%{_lib} -Wl,--rpath=/opt/shibboleth/%{_lib}" CPPFLAGS="${CPPFLAGS} -I/opt/shibboleth/include"
 make %{?_smp_mflags}
 
 
@@ -51,7 +50,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/gss/mech_eap.so
 %exclude %{_libdir}/gss/mech_eap.la
 %{_includedir}/gssapi/*.h
-#%exclude %{_libdir}/krb5/plugins/authdata/*la
+%exclude %{_libdir}/krb5/plugins/authdata/*
 #%{_libdir}/krb5/plugins/authdata/*.so
 
 
index 3cb2d50..c16ef62 100644 (file)
@@ -111,7 +111,7 @@ Sample usage is given below. Substitute <user>, <pass> and <host>
 appropriately (<host> is the name of the host running the server,
 not the RADIUS server).
 
-% gss-client -port 5555 -spnego -mech "{1 3 6 1 4 1 5322 22 1 18}" \
+% gss-client -port 5555 -spnego -mech "{1 3 6 1 5 5 15 1 1 18}" \
   -user <user>@<realm> -pass <pass> <host> host@<host> \
   "Testing GSS EAP"
 % gss-server -port 5555 -export host@<host>
index d0a94d1..cf58667 100644 (file)
@@ -16,8 +16,8 @@ Shibboleth
 * Add a mapping from the PAC RADIUS attribute to urn:mspac: in the file
   /usr/local/etc/shibboleth/attribute-map.xml:
 
-  <GSSAPIAttribute name="urn:ietf:params:gss-eap:radius-avp urn:x-radius:1679163525"
-                   id="urn:mspac:" binary="true"/>
+  <GSSAPIAttribute name="urn:ietf:params:gss:radius-attribute 26.25622.133"
+   id="urn:mspac:" binary="true"/>
 
 FreeRADIUS
 ----------
@@ -46,7 +46,7 @@ on OS X it was necessary to start it with -M single to function under gdb.
 
 For the client, the GSS EAP mechanism can be specified on the command line:
 
-smbclient --password samba --mechanism 1.3.6.1.4.1.5322.22.1.18 '\\host\share'".
+smbclient --password samba --mechanism 1.3.6.1.5.5.15.1.1.18 '\\host\share'".
 
 There is no Moonshot SSPI implementation as yet, so it is not possible to test
 with a Windows client.
index 0111459..78d92c8 100644 (file)
@@ -1,3 +1,4 @@
+- draft-ietf-radext-radius-extensions
 - integration with initiator-side EAP channel bindings
 - investigate initiator-side credential locking
 - always intern OIDs so they never need to be freed
index 5b878b1..9888097 100644 (file)
@@ -59,7 +59,7 @@ static OM_uint32
 acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
 {
     OM_uint32 major, tmpMinor;
-    VALUE_PAIR *vp;
+    rs_const_avp *vp;
     gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
 
     /* Cache encryption type derived from selected mechanism OID */
@@ -72,9 +72,10 @@ acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
 
     major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
                                   PW_USER_NAME, 0, &vp);
-    if (major == GSS_S_COMPLETE && vp->length) {
-        nameBuf.length = vp->length;
-        nameBuf.value = vp->vp_strvalue;
+    if (major == GSS_S_COMPLETE && rs_avp_length(vp) != 0) {
+        rs_avp_octets_value_byref((rs_avp *)vp,
+                                  (unsigned char **)&nameBuf.value,
+                                  &nameBuf.length);
     } else {
         ctx->gssFlags |= GSS_C_ANON_FLAG;
     }
@@ -88,15 +89,15 @@ acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
         return major;
 
     major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
-                                  PW_MS_MPPE_SEND_KEY, VENDORPEC_MS, &vp);
+                                  PW_MS_MPPE_SEND_KEY, VENDORPEC_MICROSOFT, &vp);
     if (GSS_ERROR(major)) {
         *minor = GSSEAP_KEY_UNAVAILABLE;
         return GSS_S_UNAVAILABLE;
     }
 
     major = gssEapDeriveRfc3961Key(minor,
-                                   vp->vp_octets,
-                                   vp->length,
+                                   rs_avp_octets_value_const_ptr(vp),
+                                   rs_avp_length(vp),
                                    ctx->encryptionType,
                                    &ctx->rfc3961Key);
     if (GSS_ERROR(major))
@@ -287,7 +288,7 @@ importInitiatorIdentity(OM_uint32 *minor,
 static OM_uint32
 setInitiatorIdentity(OM_uint32 *minor,
                      gss_ctx_id_t ctx,
-                     VALUE_PAIR **vps)
+                     struct rs_packet *req)
 {
     OM_uint32 major, tmpMinor;
     gss_buffer_desc nameBuf;
@@ -303,7 +304,7 @@ setInitiatorIdentity(OM_uint32 *minor,
         if (GSS_ERROR(major))
             return major;
 
-        major = gssEapRadiusAddAvp(minor, vps, PW_USER_NAME, 0, &nameBuf);
+        major = gssEapRadiusAddAvp(minor, req, PW_USER_NAME, 0, &nameBuf);
         if (GSS_ERROR(major))
             return major;
 
@@ -320,7 +321,7 @@ setInitiatorIdentity(OM_uint32 *minor,
 static OM_uint32
 setAcceptorIdentity(OM_uint32 *minor,
                     gss_ctx_id_t ctx,
-                    VALUE_PAIR **vps)
+                    struct rs_packet *req)
 {
     OM_uint32 major;
     gss_buffer_desc nameBuf;
@@ -349,9 +350,9 @@ setAcceptorIdentity(OM_uint32 *minor,
     /* Acceptor-Service-Name */
     krbPrincComponentToGssBuffer(krbPrinc, 0, &nameBuf);
 
-    major = gssEapRadiusAddAvp(minor, vps,
+    major = gssEapRadiusAddAvp(minor, req,
                                PW_GSS_ACCEPTOR_SERVICE_NAME,
-                               VENDORPEC_UKERNA,
+                               0,
                                &nameBuf);
     if (GSS_ERROR(major))
         return major;
@@ -359,9 +360,9 @@ setAcceptorIdentity(OM_uint32 *minor,
     /* Acceptor-Host-Name */
     krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf);
 
-    major = gssEapRadiusAddAvp(minor, vps,
+    major = gssEapRadiusAddAvp(minor, req,
                                PW_GSS_ACCEPTOR_HOST_NAME,
-                               VENDORPEC_UKERNA,
+                               0,
                                &nameBuf);
     if (GSS_ERROR(major))
         return major;
@@ -373,24 +374,25 @@ setAcceptorIdentity(OM_uint32 *minor,
         if (*minor != 0)
             return GSS_S_FAILURE;
 
-        major = gssEapRadiusAddAvp(minor, vps,
-                                   PW_GSS_ACCEPTOR_SERVICE_SPECIFIC,
-                                   VENDORPEC_UKERNA,
+        major = gssEapRadiusAddAvp(minor, req,
+                                   PW_GSS_ACCEPTOR_SERVICE_SPECIFICS,
+                                   0,
                                    &nameBuf);
-
-        if (GSS_ERROR(major)) {
-            krbFreeUnparsedName(krbContext, &nameBuf);
+#ifdef HAVE_HEIMDAL_VERSION
+        krb5_xfree(ssi);
+#else
+        krb5_free_unparsed_name(krbContext, ssi);
+#endif
+        if (GSS_ERROR(major))
             return major;
-        }
-        krbFreeUnparsedName(krbContext, &nameBuf);
     }
 
     krbPrincRealmToGssBuffer(krbPrinc, &nameBuf);
     if (nameBuf.length != 0) {
         /* Acceptor-Realm-Name */
-        major = gssEapRadiusAddAvp(minor, vps,
+        major = gssEapRadiusAddAvp(minor, req,
                                    PW_GSS_ACCEPTOR_REALM_NAME,
-                                   VENDORPEC_UKERNA,
+                                   0,
                                    &nameBuf);
         if (GSS_ERROR(major))
             return major;
@@ -460,7 +462,7 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
     struct rs_connection *rconn;
     struct rs_request *request = NULL;
     struct rs_packet *req = NULL, *resp = NULL;
-    struct radius_packet *frreq, *frresp;
+    int isAccessChallenge;
 
     if (ctx->acceptorCtx.radContext == NULL) {
         /* May be NULL from an imported partial context */
@@ -481,23 +483,22 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
         major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
         goto cleanup;
     }
-    frreq = rs_packet_frpkt(req);
 
-    major = setInitiatorIdentity(minor, ctx, &frreq->vps);
+    major = setInitiatorIdentity(minor, ctx, req);
     if (GSS_ERROR(major))
         goto cleanup;
 
-    major = setAcceptorIdentity(minor, ctx, &frreq->vps);
+    major = setAcceptorIdentity(minor, ctx, req);
     if (GSS_ERROR(major))
         goto cleanup;
 
-    major = gssEapRadiusAddAvp(minor, &frreq->vps,
+    major = gssEapRadiusAddAvp(minor, req,
                                PW_EAP_MESSAGE, 0, inputToken);
     if (GSS_ERROR(major))
         goto cleanup;
 
     if (ctx->acceptorCtx.state.length != 0) {
-        major = gssEapRadiusAddAvp(minor, &frreq->vps, PW_STATE, 0,
+        major = gssEapRadiusAddAvp(minor, req, PW_STATE, 0,
                                    &ctx->acceptorCtx.state);
         if (GSS_ERROR(major))
             goto cleanup;
@@ -520,12 +521,15 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
 
     GSSEAP_ASSERT(resp != NULL);
 
-    frresp = rs_packet_frpkt(resp);
-    switch (frresp->code) {
+    isAccessChallenge = 0;
+
+    switch (rs_packet_code(resp)) {
     case PW_ACCESS_CHALLENGE:
-    case PW_AUTHENTICATION_ACK:
+        isAccessChallenge = 1;
+        break;
+    case PW_ACCESS_ACCEPT:
         break;
-    case PW_AUTHENTICATION_REJECT:
+    case PW_ACCESS_REJECT:
         *minor = GSSEAP_RADIUS_AUTH_FAILURE;
         major = GSS_S_DEFECTIVE_CREDENTIAL;
         goto cleanup;
@@ -537,23 +541,27 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
         break;
     }
 
-    major = gssEapRadiusGetAvp(minor, frresp->vps, PW_EAP_MESSAGE, 0,
+    major = gssEapRadiusGetAvp(minor, resp, PW_EAP_MESSAGE, 0,
                                outputToken, TRUE);
-    if (major == GSS_S_UNAVAILABLE && frresp->code == PW_ACCESS_CHALLENGE) {
+    if (major == GSS_S_UNAVAILABLE && isAccessChallenge) {
         *minor = GSSEAP_MISSING_EAP_REQUEST;
         major = GSS_S_DEFECTIVE_TOKEN;
         goto cleanup;
     } else if (GSS_ERROR(major))
         goto cleanup;
 
-    if (frresp->code == PW_ACCESS_CHALLENGE) {
-        major = gssEapRadiusGetAvp(minor, frresp->vps, PW_STATE, 0,
+    if (isAccessChallenge) {
+        major = gssEapRadiusGetAvp(minor, resp, PW_STATE, 0,
                                    &ctx->acceptorCtx.state, TRUE);
         if (GSS_ERROR(major) && *minor != GSSEAP_NO_SUCH_ATTR)
             goto cleanup;
     } else {
-        ctx->acceptorCtx.vps = frresp->vps;
-        frresp->vps = NULL;
+        rs_avp **vps;
+
+        rs_packet_avps(resp, &vps);
+
+        ctx->acceptorCtx.vps = *vps;
+        *vps = NULL;
 
         major = acceptReadyEap(minor, ctx, cred);
         if (GSS_ERROR(major))
@@ -630,39 +638,41 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
                                  gss_buffer_t outputToken GSSEAP_UNUSED,
                                  OM_uint32 *smFlags GSSEAP_UNUSED)
 {
-    OM_uint32 major;
-    gss_iov_buffer_desc iov[2];
+    krb5_error_code code;
+    krb5_context krbContext;
+    krb5_data data;
+    krb5_checksum cksum;
+    krb5_boolean valid = FALSE;
 
-    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
-    iov[0].buffer.length = 0;
-    iov[0].buffer.value = NULL;
+    if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS ||
+        chanBindings->application_data.length == 0)
+        return GSS_S_CONTINUE_NEEDED;
 
-    iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM | GSS_IOV_BUFFER_FLAG_ALLOCATED;
+    GSSEAP_KRB_INIT(&krbContext);
 
-    /* XXX necessary because decrypted in place and we verify it later */
-    major = duplicateBuffer(minor, inputToken, &iov[1].buffer);
-    if (GSS_ERROR(major))
-        return major;
+    KRB_DATA_INIT(&data);
 
-    major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
-                                    iov, 2, TOK_TYPE_WRAP);
-    if (GSS_ERROR(major)) {
-        gssEapReleaseIov(iov, 2);
-        return major;
+    gssBufferToKrbData(&chanBindings->application_data, &data);
+
+    KRB_CHECKSUM_INIT(&cksum, ctx->checksumType, inputToken);
+
+    code = krb5_c_verify_checksum(krbContext, &ctx->rfc3961Key,
+                                  KEY_USAGE_GSSEAP_CHBIND_MIC,
+                                  &data, &cksum, &valid);
+    if (code != 0) {
+        *minor = code;
+        return GSS_S_FAILURE;
     }
 
-    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
-        !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
-        major = GSS_S_BAD_BINDINGS;
+    if (valid == FALSE) {
         *minor = GSSEAP_BINDINGS_MISMATCH;
-    } else {
-        major = GSS_S_CONTINUE_NEEDED;
-        *minor = 0;
+        return GSS_S_BAD_BINDINGS;
     }
 
-    gssEapReleaseIov(iov, 2);
+    ctx->flags |= CTX_FLAG_CHANNEL_BINDINGS_VERIFIED;
 
-    return major;
+    *minor = 0;
+    return GSS_S_CONTINUE_NEEDED;
 }
 
 static OM_uint32
@@ -673,13 +683,27 @@ eapGssSmAcceptInitiatorMIC(OM_uint32 *minor,
                            gss_OID mech GSSEAP_UNUSED,
                            OM_uint32 reqFlags GSSEAP_UNUSED,
                            OM_uint32 timeReq GSSEAP_UNUSED,
-                           gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+                           gss_channel_bindings_t chanBindings,
                            gss_buffer_t inputToken,
                            gss_buffer_t outputToken GSSEAP_UNUSED,
                            OM_uint32 *smFlags GSSEAP_UNUSED)
 {
     OM_uint32 major;
 
+    /*
+     * The channel binding token is optional, however if the caller indicated
+     * bindings we must raise an error if it was absent.
+     *
+     * In the future, we might use a context option to allow the caller to
+     * indicate that missing bindings are acceptable.
+     */
+    if (chanBindings != NULL &&
+        chanBindings->application_data.length != 0 &&
+        (ctx->flags & CTX_FLAG_CHANNEL_BINDINGS_VERIFIED) == 0) {
+        *minor = GSSEAP_MISSING_BINDINGS;
+        return GSS_S_BAD_BINDINGS;
+    }
+
     major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
     if (GSS_ERROR(major))
         return major;
@@ -798,7 +822,7 @@ static struct gss_eap_sm eapGssAcceptorSm[] = {
         ITOK_TYPE_GSS_CHANNEL_BINDINGS,
         ITOK_TYPE_NONE,
         GSSEAP_STATE_INITIATOR_EXTS,
-        SM_ITOK_FLAG_REQUIRED,
+        0,
         eapGssSmAcceptGssChannelBindings,
     },
     {
@@ -819,6 +843,13 @@ static struct gss_eap_sm eapGssAcceptorSm[] = {
 #endif
     {
         ITOK_TYPE_NONE,
+        ITOK_TYPE_ACCEPTOR_NAME_RESP,
+        GSSEAP_STATE_ACCEPTOR_EXTS,
+        0,
+        eapGssSmAcceptAcceptorName
+    },
+    {
+        ITOK_TYPE_NONE,
         ITOK_TYPE_ACCEPTOR_MIC,
         GSSEAP_STATE_ACCEPTOR_EXTS,
         0,
@@ -864,13 +895,11 @@ gssEapAcceptSecContext(OM_uint32 *minor,
      * credential handle.
      */
 
-    /*
-     * Calling gssEapInquireCred() forces the default acceptor credential name
-     * to be resolved.
-     */
-    major = gssEapInquireCred(minor, cred, &ctx->acceptorName, NULL, NULL, NULL);
-    if (GSS_ERROR(major))
-        goto cleanup;
+    if (cred->name != GSS_C_NO_NAME) {
+        major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
 
     major = gssEapSmStep(minor,
                          cred,
index edadf3e..1da8354 100644 (file)
@@ -42,5 +42,5 @@ gss_compare_name(OM_uint32 *minor,
                  gss_name_t name2,
                  int *name_equal)
 {
-    return gssEapCompareName(minor, name1, name2, name_equal);
+    return gssEapCompareName(minor, name1, name2, 0, name_equal);
 }
index 8f3f296..235606f 100644 (file)
@@ -9,13 +9,13 @@ VENDOR        UKERNA                          25622
 
 BEGIN-VENDOR UKERNA
 
-ATTRIBUTE      GSS-Acceptor-Service-Name       128     string
-ATTRIBUTE      GSS-Acceptor-Host-Name          129     string
-ATTRIBUTE      GSS-Acceptor-Service-Specific   130     string
-ATTRIBUTE      GSS-Acceptor-Realm-Name         131     string
-ATTRIBUTE      SAML-AAA-Assertion              132     string
-ATTRIBUTE      MS-Windows-Auth-Data            133     octets
-ATTRIBUTE      MS-Windows-Group-Sid            134     string
+ATTRIBUTE      GSS-Acceptor-Service-Name-VS            128     string
+ATTRIBUTE      GSS-Acceptor-Host-Name-VS               129     string
+ATTRIBUTE      GSS-Acceptor-Service-Specific-VS        130     string
+ATTRIBUTE      GSS-Acceptor-Realm-Name-VS              131     string
+ATTRIBUTE      SAML-AAA-Assertion                      132     string
+ATTRIBUTE      MS-Windows-Auth-Data                    133     octets
+ATTRIBUTE      MS-Windows-Group-Sid                    134     string
 ATTRIBUTE      EAP-Channel-Binding-Message     135     octets
 
 END-VENDOR UKERNA
index e5be6d8..3b74366 100644 (file)
@@ -121,6 +121,11 @@ gssEapExportSecContext(OM_uint32 *minor,
     key.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
     key.value  = KRB_KEY_DATA(&ctx->rfc3961Key);
 
+    /*
+     * As a shortcut, we omit the mechanism OID of the initiator name because
+     * we know it will match the context mechanism. The acceptor name mech OID
+     * is always included.
+     */
     if (ctx->initiatorName != GSS_C_NO_NAME) {
         major = gssEapExportNameInternal(minor, ctx->initiatorName,
                                          &initiatorName,
@@ -132,7 +137,7 @@ gssEapExportSecContext(OM_uint32 *minor,
     if (ctx->acceptorName != GSS_C_NO_NAME) {
         major = gssEapExportNameInternal(minor, ctx->acceptorName,
                                          &acceptorName,
-                                         EXPORT_NAME_FLAG_COMPOSITE);
+                                         EXPORT_NAME_FLAG_OID | EXPORT_NAME_FLAG_COMPOSITE);
         if (GSS_ERROR(major))
             goto cleanup;
     }
index 7fd55df..19f1770 100644 (file)
@@ -90,28 +90,11 @@ typedef const gss_OID_desc *gss_const_OID;
 #include <wpabuf.h>
 
 #ifdef GSSEAP_ENABLE_ACCEPTOR
-/* FreeRADIUS headers */
-#ifdef __cplusplus
-extern "C" {
-#ifndef WIN32
-#define operator fr_operator
-#endif
-#endif
-#include <freeradius/libradius.h>
-#include <freeradius/radius.h>
-
-#undef pid_t
-
 /* libradsec headers */
 #include <radsec/radsec.h>
 #include <radsec/request.h>
-#ifdef __cplusplus
-#ifndef WIN32
-#undef operator
+#include <radsec/radius.h>
 #endif
-}
-#endif
-#endif /* GSSEAP_ENABLE_ACCEPTOR */
 
 #include "gsseap_err.h"
 #include "radsec_err.h"
@@ -178,6 +161,7 @@ struct gss_cred_id_struct
 
 #define CTX_FLAG_INITIATOR                  0x00000001
 #define CTX_FLAG_KRB_REAUTH                 0x00000002
+#define CTX_FLAG_CHANNEL_BINDINGS_VERIFIED  0x00000004
 
 #define CTX_IS_INITIATOR(ctx)               (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
 
@@ -211,7 +195,7 @@ struct gss_eap_acceptor_ctx {
     struct rs_connection *radConn;
     char *radServer;
     gss_buffer_desc state;
-    VALUE_PAIR *vps;
+    rs_avp *vps;
 };
 #endif
 
@@ -260,6 +244,10 @@ struct gss_ctx_id_struct
 #define KEY_USAGE_INITIATOR_SEAL            24
 #define KEY_USAGE_INITIATOR_SIGN            25
 
+#define KEY_USAGE_GSSEAP_CHBIND_MIC         60
+#define KEY_USAGE_GSSEAP_ACCTOKEN_MIC       61
+#define KEY_USAGE_GSSEAP_INITOKEN_MIC       62
+
 /* accept_sec_context.c */
 OM_uint32
 gssEapAcceptSecContext(OM_uint32 *minor,
@@ -341,9 +329,12 @@ gssEapDisplayStatus(OM_uint32 *minor,
 #define IS_WIRE_ERROR(err)              ((err) > GSSEAP_RESERVED && \
                                          (err) <= GSSEAP_RADIUS_PROT_FAILURE)
 
-/* upper bound of RADIUS error range must be kept in sync with radsec.h */
+#ifdef GSSEAP_ENABLE_ACCEPTOR
 #define IS_RADIUS_ERROR(err)            ((err) >= ERROR_TABLE_BASE_rse && \
-                                         (err) <= ERROR_TABLE_BASE_rse + 20)
+                                         (err) <= ERROR_TABLE_BASE_rse + RSE_MAX)
+#else
+#define IS_RADIUS_ERROR(err)            (0)
+#endif
 
 /* exchange_meta_data.c */
 OM_uint32 GSSAPI_CALLCONV
@@ -380,7 +371,6 @@ gssEapPseudoRandom(OM_uint32 *minor,
                    gss_ctx_id_t ctx,
                    int prf_key,
                    const gss_buffer_t prf_in,
-                   ssize_t desired_output_len,
                    gss_buffer_t prf_out);
 
 /* query_mechanism_info.c */
index e26911a..2f0774b 100644 (file)
@@ -70,6 +70,7 @@ error_code GSSEAP_BAD_SERVICE_NAME,             "Name is not a valid service nam
 error_code GSSEAP_BAD_INITIATOR_NAME,           "Initiator identity must be a valid name"
 error_code GSSEAP_NO_HOSTNAME,                  "Could not determine local host name"
 error_code GSSEAP_NO_ACCEPTOR_NAME,             "Could not determine acceptor identity"
+error_code GSSEAP_WRONG_ACCEPTOR_NAME,          "Acceptor identity different than expected"
 error_code GSSEAP_BAD_ACCEPTOR_NAME,            "Acceptor name is too long or has too many components"
 error_code GSSEAP_BAD_NAME_TOKEN,               "Name token is malformed or corrupt"
 error_code GSSEAP_NO_LOCAL_MAPPING,             "Unable to map name to a local identity"
@@ -157,6 +158,7 @@ error_code GSSEAP_SHIB_LISTENER_FAILURE,        "Failed to communicate with loca
 # Extensions
 #
 error_code GSSEAP_BINDINGS_MISMATCH,            "Channel bindings do not match"
+error_code GSSEAP_MISSING_BINDINGS,             "Channel binding token missing"
 error_code GSSEAP_NO_MECHGLUE_SYMBOL,           "Could not find symbol in mechanism glue"
 error_code GSSEAP_BAD_INVOCATION,               "Bad mechanism invoke OID"
 
index 1533a16..a0ebb8c 100644 (file)
@@ -209,11 +209,12 @@ importKerberosKey(OM_uint32 *minor,
 
 static OM_uint32
 importName(OM_uint32 *minor,
+           gss_OID mech,
            unsigned char **pBuf,
            size_t *pRemain,
            gss_name_t *pName)
 {
-    OM_uint32 major;
+    OM_uint32 major, tmpMinor, flags;
     unsigned char *p = *pBuf;
     size_t remain = *pRemain;
     gss_buffer_desc tmp;
@@ -232,10 +233,21 @@ importName(OM_uint32 *minor,
 
         tmp.value = p + 4;
 
-        major = gssEapImportNameInternal(minor, &tmp, pName,
-                                         EXPORT_NAME_FLAG_COMPOSITE);
+        flags = EXPORT_NAME_FLAG_COMPOSITE;
+        if (mech == GSS_C_NO_OID)
+            flags |= EXPORT_NAME_FLAG_OID;
+
+        major = gssEapImportNameInternal(minor, &tmp, pName, flags);
         if (GSS_ERROR(major))
             return major;
+
+        if ((flags & EXPORT_NAME_FLAG_OID) == 0) {
+            major = gssEapCanonicalizeOid(minor, mech, 0, &(*pName)->mechanismUsed);
+            if (GSS_ERROR(major)) {
+                gssEapReleaseName(&tmpMinor, pName);
+                return major;
+            }
+        }
     }
 
     *pBuf    += 4 + tmp.length;
@@ -288,11 +300,12 @@ gssEapImportContext(OM_uint32 *minor,
     if (GSS_ERROR(major))
         return major;
 
-    major = importName(minor, &p, &remain, &ctx->initiatorName);
+    /* Initiator name OID matches the context mechanism, so it's not encoded */
+    major = importName(minor, ctx->mechanismUsed, &p, &remain, &ctx->initiatorName);
     if (GSS_ERROR(major))
         return major;
 
-    major = importName(minor, &p, &remain, &ctx->acceptorName);
+    major = importName(minor, GSS_C_NO_OID, &p, &remain, &ctx->acceptorName);
     if (GSS_ERROR(major))
         return major;
 
index 6a8de69..6cb4be0 100644 (file)
@@ -718,17 +718,45 @@ eapGssSmInitAcceptorName(OM_uint32 *minor,
                                   outputToken, NULL);
         if (GSS_ERROR(major))
             return major;
-    } else if (inputToken != GSS_C_NO_BUFFER &&
-               ctx->acceptorName == GSS_C_NO_NAME) {
-        /* Accept target name hint from acceptor */
+    } else if (inputToken != GSS_C_NO_BUFFER) {
+        OM_uint32 tmpMinor;
+        gss_name_t nameHint;
+        int equal;
+
+        /* Accept target name hint from acceptor or verify acceptor */
         major = gssEapImportName(minor, inputToken,
                                  GSS_C_NT_USER_NAME,
                                  ctx->mechanismUsed,
-                                 &ctx->acceptorName);
+                                 &nameHint);
         if (GSS_ERROR(major))
             return major;
+
+        if (ctx->acceptorName != GSS_C_NO_NAME) {
+            /* verify name hint matched asserted acceptor name  */
+            major = gssEapCompareName(minor,
+                                      nameHint,
+                                      ctx->acceptorName,
+                                      COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS,
+                                      &equal);
+            if (GSS_ERROR(major)) {
+                gssEapReleaseName(&tmpMinor, &nameHint);
+                return major;
+            }
+
+            gssEapReleaseName(&tmpMinor, &nameHint);
+
+            if (!equal) {
+                *minor = GSSEAP_WRONG_ACCEPTOR_NAME;
+                return GSS_S_DEFECTIVE_TOKEN;
+            }
+        } else { /* acceptor name is no_name */
+            /* accept acceptor name hint */
+            ctx->acceptorName = nameHint;
+            nameHint = GSS_C_NO_NAME;
+        }
     }
 
+
     /*
      * Currently, other parts of the code assume that the acceptor name
      * is available, hence this check.
@@ -925,21 +953,45 @@ eapGssSmInitGssChannelBindings(OM_uint32 *minor,
                                OM_uint32 *smFlags)
 {
     OM_uint32 major;
-    gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
+    krb5_error_code code;
+    krb5_context krbContext;
+    krb5_data data;
+    krb5_checksum cksum;
+    gss_buffer_desc cksumBuffer;
 
-    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
-        buffer = chanBindings->application_data;
+    if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS ||
+        chanBindings->application_data.length == 0)
+        return GSS_S_CONTINUE_NEEDED;
 
-    major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
-                       &buffer, NULL, outputToken);
-    if (GSS_ERROR(major))
-        return major;
+    GSSEAP_KRB_INIT(&krbContext);
+
+    KRB_DATA_INIT(&data);
+
+    gssBufferToKrbData(&chanBindings->application_data, &data);
 
-    GSSEAP_ASSERT(outputToken->value != NULL);
+    code = krb5_c_make_checksum(krbContext, ctx->checksumType,
+                                &ctx->rfc3961Key,
+                                KEY_USAGE_GSSEAP_CHBIND_MIC,
+                                &data, &cksum);
+    if (code != 0) {
+        *minor = code;
+        return GSS_S_FAILURE;
+    }
+
+    cksumBuffer.length = KRB_CHECKSUM_LENGTH(&cksum);
+    cksumBuffer.value  = KRB_CHECKSUM_DATA(&cksum);
+
+    major = duplicateBuffer(minor, &cksumBuffer, outputToken);
+    if (GSS_ERROR(major)) {
+        krb5_free_checksum_contents(krbContext, &cksum);
+        return major;
+    }
 
     *minor = 0;
     *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
 
+    krb5_free_checksum_contents(krbContext, &cksum);
+
     return GSS_S_CONTINUE_NEEDED;
 }
 
@@ -969,7 +1021,7 @@ eapGssSmInitInitiatorMIC(OM_uint32 *minor,
 
     return GSS_S_CONTINUE_NEEDED;
 }
+
 #ifdef GSSEAP_ENABLE_REAUTH
 static OM_uint32
 eapGssSmInitReauthCreds(OM_uint32 *minor,
@@ -1034,7 +1086,8 @@ static struct gss_eap_sm eapGssInitiatorSm[] = {
     {
         ITOK_TYPE_ACCEPTOR_NAME_RESP,
         ITOK_TYPE_ACCEPTOR_NAME_REQ,
-        GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE,
+        GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE |
+        GSSEAP_STATE_ACCEPTOR_EXTS,
         0,
         eapGssSmInitAcceptorName
     },
@@ -1084,7 +1137,7 @@ static struct gss_eap_sm eapGssInitiatorSm[] = {
         ITOK_TYPE_NONE,
         ITOK_TYPE_GSS_CHANNEL_BINDINGS,
         GSSEAP_STATE_INITIATOR_EXTS,
-        SM_ITOK_FLAG_REQUIRED,
+        0,
         eapGssSmInitGssChannelBindings
     },
     {
index d37818d..305145c 100644 (file)
@@ -57,15 +57,21 @@ gss_inquire_context(OM_uint32 *minor,
     GSSEAP_MUTEX_LOCK(&ctx->mutex);
 
     if (src_name != NULL) {
-        major = gssEapDuplicateName(minor, ctx->initiatorName, src_name);
-        if (GSS_ERROR(major))
-            goto cleanup;
+        if (ctx->initiatorName != GSS_C_NO_NAME) {
+            major = gssEapDuplicateName(minor, ctx->initiatorName, src_name);
+            if (GSS_ERROR(major))
+                goto cleanup;
+        } else
+            *src_name = GSS_C_NO_NAME;
     }
 
     if (targ_name != NULL) {
-        major = gssEapDuplicateName(minor, ctx->acceptorName, targ_name);
-        if (GSS_ERROR(major))
-            goto cleanup;
+        if (ctx->acceptorName != GSS_C_NO_NAME) {
+            major = gssEapDuplicateName(minor, ctx->acceptorName, targ_name);
+            if (GSS_ERROR(major))
+                goto cleanup;
+        } else
+            *targ_name = GSS_C_NO_NAME;
     }
 
     if (lifetime_rec != NULL) {
index 7435f2e..bde7e1c 100644 (file)
@@ -156,8 +156,16 @@ inquireNegoExKey(OM_uint32 *minor,
 
     keySize = KRB_KEY_LENGTH(&ctx->rfc3961Key);
 
-    major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt,
-                               keySize, &key);
+    key.value = GSSEAP_MALLOC(keySize);
+    if (key.value == NULL) {
+        major = GSS_S_FAILURE;
+        *minor = ENOMEM;
+        goto cleanup;
+    }
+
+    key.length = keySize;
+
+    major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt, &key);
     if (GSS_ERROR(major))
         goto cleanup;
 
index 258a43a..3d2a2a8 100644 (file)
@@ -4,5 +4,5 @@
 # Any encryption type supported by Kerberos can be defined as the
 # last element of the OID arc.
 #
-eap-aes128             1.3.6.1.4.1.5322.22.1.17        mech_eap.so
-eap-aes256             1.3.6.1.4.1.5322.22.1.18        mech_eap.so
+eap-aes128             1.3.6.1.5.5.15.1.1.17           mech_eap.so
+eap-aes256             1.3.6.1.5.5.15.1.1.18           mech_eap.so
index 61d1f2a..ad079b4 100644 (file)
@@ -64,7 +64,6 @@ gssEapPseudoRandom(OM_uint32 *minor,
                    gss_ctx_id_t ctx,
                    int prf_key,
                    const gss_buffer_t prf_in,
-                   ssize_t desired_output_len,
                    gss_buffer_t prf_out)
 {
     krb5_error_code code;
@@ -74,9 +73,7 @@ gssEapPseudoRandom(OM_uint32 *minor,
     krb5_data t, ns;
     unsigned char *p;
     krb5_context krbContext;
-
-    prf_out->length = 0;
-    prf_out->value = NULL;
+    ssize_t desired_output_len = prf_out->length;
 
     *minor = 0;
 
@@ -91,13 +88,6 @@ gssEapPseudoRandom(OM_uint32 *minor,
         goto cleanup;
     }
 
-    prf_out->value = GSSEAP_MALLOC(desired_output_len);
-    if (prf_out->value == NULL) {
-        code = ENOMEM;
-        goto cleanup;
-    }
-    prf_out->length = desired_output_len;
-
     code = krb5_c_prf_length(krbContext,
                              ctx->encryptionType,
                              &prflen);
@@ -146,7 +136,7 @@ cleanup:
         GSSEAP_FREE(ns.data);
     }
 #ifdef HAVE_HEIMDAL_VERSION
-    krb5_free_data_contents(krbContext, &t);
+    krb5_data_free(&t);
 #else
     if (t.data != NULL) {
         memset(t.data, 0, t.length);
@@ -181,14 +171,25 @@ gss_pseudo_random(OM_uint32 *minor,
 
     GSSEAP_MUTEX_LOCK(&ctx->mutex);
 
-    if (CTX_IS_ESTABLISHED(ctx)) {
-        major = gssEapPseudoRandom(minor, ctx, prf_key,
-                                   prf_in, desired_output_len, prf_out);
-    } else {
+    if (!CTX_IS_ESTABLISHED(ctx)) {
         major = GSS_S_NO_CONTEXT;
         *minor = GSSEAP_CONTEXT_INCOMPLETE;
+        goto cleanup;
+    }
+
+    prf_out->value = GSSEAP_MALLOC(desired_output_len);
+    if (prf_out->value == NULL) {
+        major = GSS_S_FAILURE;
+        *minor = ENOMEM;
+        goto cleanup;
     }
 
+    prf_out->length = desired_output_len;
+
+    major = gssEapPseudoRandom(minor, ctx, prf_key,
+                               prf_in, prf_out);
+
+cleanup:
     GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
 
     return major;
index 27f895a..cd3a163 100644 (file)
@@ -1,5 +1,3 @@
-dictionary = "/usr/local/etc/raddb/dictionary"
-
 realm gss-eap {
     type = "UDP"
     timeout = 5
index 71f3473..9a606ab 100644 (file)
@@ -73,7 +73,9 @@
 #include <krb5.h>
 
 #ifdef WIN32
-#define inline __inline
+# ifndef __cplusplus
+# define inline __inline
+# endif
 #define snprintf _snprintf
 #endif
 
@@ -379,6 +381,16 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
 
 #define KRB_DATA_INIT(d)        krb5_data_zero((d))
 
+#define KRB_CHECKSUM_TYPE(c)    ((c)->cksumtype)
+#define KRB_CHECKSUM_LENGTH(c)  ((c)->checksum.length)
+#define KRB_CHECKSUM_DATA(c)    ((c)->checksum.data)
+
+#define KRB_CHECKSUM_INIT(cksum, type, d)      do { \
+        (cksum)->cksumtype = (type);                \
+        (cksum)->checksum.length = (d)->length;     \
+        (cksum)->checksum.data = (d)->value;        \
+    } while (0)
+
 #else
 
 #define KRB_TIME_FOREVER        KRB5_INT32_MAX
@@ -405,6 +417,16 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
         (d)->data = NULL;                   \
     } while (0)
 
+#define KRB_CHECKSUM_TYPE(c)    ((c)->checksum_type)
+#define KRB_CHECKSUM_LENGTH(c)  ((c)->length)
+#define KRB_CHECKSUM_DATA(c)    ((c)->contents)
+
+#define KRB_CHECKSUM_INIT(cksum, type, d)      do { \
+        (cksum)->checksum_type = (type);            \
+        (cksum)->length = (d)->length;              \
+        (cksum)->contents = (d)->value;             \
+    } while (0)
+
 #endif /* HAVE_HEIMDAL_VERSION */
 
 #define KRB_KEY_INIT(key)       do {        \
@@ -593,10 +615,13 @@ gssEapDisplayName(OM_uint32 *minor,
                   gss_buffer_t output_name_buffer,
                   gss_OID *output_name_type);
 
+#define COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS   0x1
+
 OM_uint32
 gssEapCompareName(OM_uint32 *minor,
                   gss_name_t name1,
                   gss_name_t name2,
+                  OM_uint32 flags,
                   int *name_equal);
 
 /* util_oid.c */
index 513a1a8..0dabd55 100644 (file)
@@ -46,7 +46,7 @@ struct radius_ad_context {
 };
 
 static krb5_data radius_ad_attr = {
-    KV5M_DATA, sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp" };
+    KV5M_DATA, sizeof("urn:authdata-aaa-radius") - 1, "urn:authdata-aaa-radius" };
 
 static krb5_error_code
 radius_ad_init(krb5_context kcontext GSSEAP_UNUSED,
index e18edc5..57bd151 100644 (file)
@@ -243,20 +243,45 @@ gssEapMakeOrVerifyTokenMIC(OM_uint32 *minor,
                            int verifyMIC)
 {
     OM_uint32 major;
-    gss_iov_buffer_desc *iov = NULL;
     size_t i = 0, j;
     enum gss_eap_token_type tokType;
     OM_uint32 micTokType;
     unsigned char wireTokType[2];
     unsigned char *innerTokTypes = NULL, *innerTokLengths = NULL;
     const struct gss_eap_token_buffer_set *tokens;
+    ssize_t checksumIndex = -1;
+
+    krb5_keyusage usage;
+    krb5_error_code code = 0;
+    krb5_context krbContext;
+    krb5_crypto_iov *kiov = NULL;
+#ifdef HAVE_HEIMDAL_VERSION
+    krb5_crypto krbCrypto = NULL;
+    krb5_cksumtype cksumType;
+#endif
+    size_t kiovCount;
+
+    GSSEAP_KRB_INIT(&krbContext);
 
     tokens = verifyMIC ? ctx->inputTokens : ctx->outputTokens;
 
     GSSEAP_ASSERT(tokens != NULL);
 
-    iov = GSSEAP_CALLOC(2 + (3 * tokens->buffers.count) + 1, sizeof(*iov));
-    if (iov == NULL) {
+#ifdef HAVE_HEIMDAL_VERSION
+    code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
+    if (code != 0)
+        goto cleanup;
+#endif
+
+    kiovCount = 2 + (3 * tokens->buffers.count) + 1;
+
+    if (verifyMIC) {
+        assert(tokens->buffers.count != 0);
+        kiovCount -= 3;
+    }
+
+    kiov = GSSEAP_CALLOC(kiovCount, sizeof(*kiov));
+    if (kiov == NULL) {
         major = GSS_S_FAILURE;
         *minor = ENOMEM;
         goto cleanup;
@@ -278,76 +303,134 @@ gssEapMakeOrVerifyTokenMIC(OM_uint32 *minor,
 
     /* Mechanism OID */
     GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID);
-    iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
-    iov[i].buffer.length = ctx->mechanismUsed->length;
-    iov[i].buffer.value = ctx->mechanismUsed->elements;
+    kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+    kiov[i].data.length = ctx->mechanismUsed->length;
+    kiov[i].data.data = ctx->mechanismUsed->elements;
     i++;
 
     /* Token type */
     if (CTX_IS_INITIATOR(ctx) ^ verifyMIC) {
         tokType = TOK_TYPE_INITIATOR_CONTEXT;
         micTokType = ITOK_TYPE_INITIATOR_MIC;
+        usage = KEY_USAGE_GSSEAP_INITOKEN_MIC;
     } else {
         tokType = TOK_TYPE_ACCEPTOR_CONTEXT;
         micTokType = ITOK_TYPE_ACCEPTOR_MIC;
+        usage = KEY_USAGE_GSSEAP_ACCTOKEN_MIC;
     }
     store_uint16_be(tokType, wireTokType);
 
-    iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
-    iov[i].buffer.length = sizeof(wireTokType);
-    iov[i].buffer.value = wireTokType;
+    kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+    kiov[i].data.length = sizeof(wireTokType);
+    kiov[i].data.data = (char *)wireTokType;
     i++;
 
     for (j = 0; j < tokens->buffers.count; j++) {
         if (verifyMIC &&
-            (tokens->types[j] & ITOK_TYPE_MASK) == micTokType)
-            continue; /* will use this slot for trailer */
+            (tokens->types[j] & ITOK_TYPE_MASK) == micTokType) {
+            continue;
+        }
 
-        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
-        iov[i].buffer.length = 4;
-        iov[i].buffer.value = &innerTokTypes[j * 4];
+        kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+        kiov[i].data.length = 4;
+        kiov[i].data.data = (char *)&innerTokTypes[j * 4];
         store_uint32_be(tokens->types[j] & ~(ITOK_FLAG_VERIFIED),
-                        iov[i].buffer.value);
+                        kiov[i].data.data);
         i++;
 
-        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
-        iov[i].buffer.length = 4;
-        iov[i].buffer.value = &innerTokLengths[j * 4];
+        kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+        kiov[i].data.length = 4;
+        kiov[i].data.data = (char *)&innerTokLengths[j * 4];
         store_uint32_be(tokens->buffers.elements[j].length,
-                        iov[i].buffer.value);
+                        kiov[i].data.data);
         i++;
 
-        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
-        iov[i].buffer = tokens->buffers.elements[j];
+        kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+        gssBufferToKrbData(&tokens->buffers.elements[j], &kiov[i].data);
         i++;
     }
 
+    kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
     if (verifyMIC) {
-        GSSEAP_ASSERT(tokenMIC->length >= 16);
+        gssBufferToKrbData(tokenMIC, &kiov[i].data);
+    } else {
+        size_t checksumSize;
 
-        GSSEAP_ASSERT(i < 2 + (3 * tokens->buffers.count));
+        code = krb5_c_checksum_length(krbContext, ctx->checksumType,
+                                      &checksumSize);
+        if (code != 0)
+            goto cleanup;
 
-        iov[i].type = GSS_IOV_BUFFER_TYPE_HEADER;
-        iov[i].buffer = *tokenMIC;
-        i++;
+        kiov[i].data.data = GSSEAP_MALLOC(checksumSize);
+        if (kiov[i].data.data == NULL) {
+            code = ENOMEM;
+            goto cleanup;
+        }
+        kiov[i].data.length = checksumSize;
+        checksumIndex = i;
+    }
+    i++;
+    GSSEAP_ASSERT(i == kiovCount);
 
-        major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
-                                        iov, i, TOK_TYPE_MIC);
+#ifdef HAVE_HEIMDAL_VERSION
+    cksumType = ctx->checksumType;
+
+    if (verifyMIC) {
+        code = krb5_verify_checksum_iov(krbContext, krbCrypto, usage,
+                                        kiov, i, &cksumType);
+    } else {
+        code = krb5_create_checksum_iov(krbContext, krbCrypto, usage,
+                                        kiov, i, &cksumType);
+    }
+#else
+    if (verifyMIC) {
+        krb5_boolean kvalid = FALSE;
+
+        code = krb5_c_verify_checksum_iov(krbContext, ctx->checksumType,
+                                          &ctx->rfc3961Key,
+                                          usage, kiov, i, &kvalid);
+        if (code == 0 && !kvalid) {
+            code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+        }
     } else {
-        iov[i++].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
-        major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL,
-                                   iov, i, TOK_TYPE_MIC);
-        if (!GSS_ERROR(major))
-            *tokenMIC = iov[i - 1].buffer;
+        code = krb5_c_make_checksum_iov(krbContext, ctx->checksumType,
+                                        &ctx->rfc3961Key,
+                                        usage, kiov, i);
+    }
+#endif /* HAVE_HEIMDAL_VERSION */
+
+    if (code == 0 && !verifyMIC) {
+        krbDataToGssBuffer(&kiov[checksumIndex].data, tokenMIC);
+        checksumIndex = -1;
     }
 
 cleanup:
-    if (iov != NULL)
-        gssEapReleaseIov(iov, tokens->buffers.count);
+    if (checksumIndex != -1)
+        GSSEAP_FREE(kiov[checksumIndex].data.data);
+    if (kiov != NULL)
+        GSSEAP_FREE(kiov);
     if (innerTokTypes != NULL)
         GSSEAP_FREE(innerTokTypes);
     if (innerTokLengths != NULL)
         GSSEAP_FREE(innerTokLengths);
+#ifdef HAVE_HEIMDAL_VERSION
+    if (krbCrypto != NULL)
+        krb5_crypto_destroy(krbContext, krbCrypto);
+#endif
+
+    *minor = code;
+
+    switch (code) {
+    case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+        major = GSS_S_BAD_SIG;
+        break;
+    case 0:
+        major = GSS_S_COMPLETE;
+        break;
+    default:
+        major = GSS_S_FAILURE;
+        break;
+    }
 
     return major;
 }
@@ -368,10 +451,5 @@ gssEapVerifyTokenMIC(OM_uint32 *minor,
                      gss_ctx_id_t ctx,
                      const gss_buffer_t tokenMIC)
 {
-    if (tokenMIC->length < 16) {
-        *minor = GSSEAP_TOK_TRUNC;
-        return GSS_S_BAD_SIG;
-    }
-
     return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, TRUE);
 }
index 746bd61..825bef5 100644 (file)
@@ -241,13 +241,14 @@ cleanup:
 gss_OID
 gssEapPrimaryMechForCred(gss_cred_id_t cred)
 {
-    gss_OID nameMech = GSS_C_NO_OID;
+    gss_OID credMech = GSS_C_NO_OID;
 
-    if (cred->mechanisms != GSS_C_NO_OID_SET &&
+    if (cred != GSS_C_NO_CREDENTIAL &&
+        cred->mechanisms != GSS_C_NO_OID_SET &&
         cred->mechanisms->count == 1)
-        nameMech = &cred->mechanisms->elements[0];
+        credMech = &cred->mechanisms->elements[0];
 
-    return nameMech;
+    return credMech;
 }
 
 OM_uint32
@@ -667,7 +668,8 @@ staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred)
             isDefaultIdentity = TRUE;
         } else {
             major = gssEapCompareName(minor, cred->name,
-                                      defaultIdentityName, &isDefaultIdentity);
+                                      defaultIdentityName, 0,
+                                      &isDefaultIdentity);
             if (GSS_ERROR(major))
                 goto cleanup;
         }
index 5eaa31e..78064f3 100644 (file)
@@ -229,7 +229,7 @@ cleanup:
     if (code != 0)
         krb5_free_keyblock_contents(krbContext, &kd);
 #ifdef HAVE_HEIMDAL_VERSION
-    krb5_free_data_contents(krbContext, &t);
+    krb5_data_free(&t);
 #else
     if (t.data != NULL) {
         memset(t.data, 0, t.length);
@@ -283,11 +283,7 @@ rfc3961ChecksumTypeForKey(OM_uint32 *minor,
     if (*minor != 0)
         return GSS_S_FAILURE;
 
-#ifdef HAVE_HEIMDAL_VERSION
-    *cksumtype = cksum.cksumtype;
-#else
-    *cksumtype = cksum.checksum_type;
-#endif
+    *cksumtype = KRB_CHECKSUM_TYPE(&cksum);
 
     krb5_free_checksum_contents(krbContext, &cksum);
 #endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */
index 958e43d..8cb7e74 100644 (file)
 #include "gssapiP_eap.h"
 
 /*
- * 1.3.6.1.4.1.5322(padl)
- *      gssEap(22)
+ * Mechanism and name types are taken from 1.3.6.1.5.5(mechanisms)
+ * assigned at http://www.iana.org/assignments/smi-numbers
+ *
+ *      abfab(15)
  *       mechanisms(1)
- *        eap-aes128-cts-hmac-sha1-96(17)
- *        eap-aes256-cts-hmac-sha1-96(18)
- *       nameTypes(2)
+ *        gss-eap-v1(1)
+ *         eap-aes128-cts-hmac-sha1-96(17)
+ *         eap-aes256-cts-hmac-sha1-96(18)
+ *       nametypes(2)
+ *        GSS_EAP_NT_EAP_NAME(1)
+ *
+ * Implementation-internal OIDs are taken from 1.3.6.1.4.1.5322(padl)
+ *      gssEap(22)
  *       apiExtensions(3)
  *        inquireSecContextByOid(1)
  *        inquireCredByOid(2)
  * canonicalized exported names.
  */
 static gss_OID_desc gssEapMechOids[] = {
-    /* 1.3.6.1.4.1.5322.22.1  */
-    { 9, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01" },
-    /* 1.3.6.1.4.1.5322.22.1.17 */
-    { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x11" },
-    /* 1.3.6.1.4.1.5322.22.1.18 */
-    { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x12" }
+    /* 1.3.6.1.5.5.15.1.1  */
+    { 8, "\x2B\x06\x01\x05\x05\x0f\x01\x01" },
+    /* 1.3.6.1.5.5.15.1.1.17  */
+    { 9, "\x2B\x06\x01\x05\x05\x0f\x01\x01\x11" },
+    /* 1.3.6.1.5.5.15.1.1.18  */
+    { 9, "\x2B\x06\x01\x05\x05\x0f\x01\x01\x12" },
 };
 
 gss_OID GSS_EAP_MECHANISM                            = &gssEapMechOids[0];
index 46282e8..3e7d14f 100644 (file)
@@ -157,13 +157,13 @@ libMoonshotResolveInitiatorCred(OM_uint32 *minor,
     MoonshotError *error = NULL;
 
     if (cred->name != GSS_C_NO_NAME) {
-        major = gssEapExportName(minor, cred->name, &initiator);
+        major = gssEapDisplayName(minor, cred->name, &initiator, NULL);
         if (GSS_ERROR(major))
             goto cleanup;
     }
 
     if (targetName != GSS_C_NO_NAME) {
-        major = gssEapExportName(minor, targetName, &target);
+        major = gssEapDisplayName(minor, targetName, &target, NULL);
         if (GSS_ERROR(major))
             goto cleanup;
     }
index 6045724..e60156c 100644 (file)
@@ -60,8 +60,8 @@
 #include "gssapiP_eap.h"
 
 static gss_OID_desc gssEapNtEapName = {
-    /* 1.3.6.1.4.1.5322.22.2.1  */
-    10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x02\x01"
+    /* 1.3.6.1.5.5.15.2.1 */
+    8, "\x2B\x06\x01\x05\x05\x0f\x02\x01"
 };
 
 gss_OID GSS_EAP_NT_EAP_NAME = &gssEapNtEapName;
@@ -702,6 +702,20 @@ gssEapDuplicateName(OM_uint32 *minor,
                                   GSS_C_NO_OID, dest_name);
 }
 
+static int
+hasRealmP(gss_name_t name)
+{
+#ifdef HAVE_HEIMDAL_VERSION
+    if (KRB_PRINC_REALM(name->krbPrincipal) != NULL &&
+        KRB_PRINC_REALM(name->krbPrincipal)[0] != '\0')
+#else
+    if (KRB_PRINC_REALM(name->krbPrincipal)->length != 0)
+#endif
+        return TRUE;
+
+    return FALSE;
+}
+
 OM_uint32
 gssEapDisplayName(OM_uint32 *minor,
                   gss_name_t name,
@@ -728,12 +742,7 @@ gssEapDisplayName(OM_uint32 *minor,
      * According to draft-ietf-abfab-gss-eap-01, when the realm is
      * absent the trailing '@' is not included.
      */
-#ifdef HAVE_HEIMDAL_VERSION
-    if (KRB_PRINC_REALM(name->krbPrincipal) == NULL ||
-        KRB_PRINC_REALM(name->krbPrincipal)[0] == '\0')
-#else
-    if (KRB_PRINC_REALM(name->krbPrincipal)->length == 0)
-#endif
+    if (!hasRealmP(name))
         flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
 
     *minor = krb5_unparse_name_flags(krbContext, name->krbPrincipal,
@@ -743,12 +752,13 @@ gssEapDisplayName(OM_uint32 *minor,
     }
 
     major = makeStringBuffer(minor, krbName, output_name_buffer);
-    if (GSS_ERROR(major)) {
-        krb5_free_unparsed_name(krbContext, krbName);
-        return major;
-    }
-
+#ifdef HAVE_HEIMDAL_VERSION
+    krb5_xfree(krbName);
+#else
     krb5_free_unparsed_name(krbContext, krbName);
+#endif
+    if (GSS_ERROR(major))
+        return major;
 
     if (output_name_buffer->length == 0) {
         name_type = GSS_C_NT_ANONYMOUS;
@@ -768,6 +778,7 @@ OM_uint32
 gssEapCompareName(OM_uint32 *minor,
                   gss_name_t name1,
                   gss_name_t name2,
+                  OM_uint32 flags,
                   int *name_equal)
 {
     krb5_context krbContext;
@@ -780,9 +791,18 @@ gssEapCompareName(OM_uint32 *minor,
         GSSEAP_KRB_INIT(&krbContext);
 
         /* krbPrincipal is immutable, so lock not required */
-        *name_equal = krb5_principal_compare(krbContext,
-                                             name1->krbPrincipal,
-                                             name2->krbPrincipal);
+        if ((flags & COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS) &&
+            (hasRealmP(name1) == FALSE || hasRealmP(name2) == FALSE)) {
+            *name_equal = krb5_principal_compare_any_realm(krbContext,
+                                                           name1->krbPrincipal,
+                                                           name2->krbPrincipal);
+        } else {
+            *name_equal = krb5_principal_compare(krbContext,
+                                                 name1->krbPrincipal,
+                                                 name2->krbPrincipal);
+        }
+    } else {
+        *name_equal = 0;
     }
 
     return GSS_S_COMPLETE;
index 71ebfb5..bb7e4d5 100644 (file)
@@ -266,7 +266,10 @@ sequenceExternalize(OM_uint32 *minor,
         *minor = GSSEAP_WRONG_SIZE;
         return GSS_S_FAILURE;
     }
-    memcpy(*buf, vqueue, sizeof(queue));
+    if (vqueue != NULL)
+        memcpy(*buf, vqueue, sizeof(queue));
+    else
+        memset(*buf, 0, sizeof(queue));
     *buf += sizeof(queue);
     *lenremain -= sizeof(queue);
 
index 9c5f36f..d8ec3df 100644 (file)
 
 #ifdef GSSEAP_ENABLE_ACCEPTOR
 
-/* stuff that should be provided by libradsec/libfreeradius-radius */
-#define VENDORATTR(vendor, attr)            (((vendor) << 16) | (attr))
+#define RS_MAP_ERROR(code)  (ERROR_TABLE_BASE_rse + (code))
 
-#ifndef ATTRID
-#define ATTRID(attr)                        ((attr) & 0xFFFF)
-#endif
+static rs_avp *copyAvps(rs_const_avp *src);
 
-static gss_buffer_desc radiusUrnPrefix = {
-    sizeof("urn:x-radius:") - 1,
-    (void *)"urn:x-radius:"
-};
+static OM_uint32
+gssEapRadiusGetAvp(OM_uint32 *minor,
+                   rs_avp *vps,
+                   const gss_eap_attrid &attrid,
+                   gss_buffer_t buffer,
+                   int concat);
 
-static VALUE_PAIR *copyAvps(const VALUE_PAIR *src);
+static OM_uint32
+gssEapRadiusAddAvp(OM_uint32 *minor,
+                   rs_avp **vps,
+                   const gss_eap_attrid &attrid,
+                   const gss_buffer_t buffer);
+
+static gss_eap_attrid
+avpToAttrId(rs_const_avp *vp)
+{
+    gss_eap_attrid attrid;
+
+    rs_avp_attrid(vp, &attrid.second, &attrid.first);
+
+    return attrid;
+}
 
 gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
 {
@@ -63,7 +76,7 @@ gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
 gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void)
 {
     if (m_vps != NULL)
-        pairfree(&m_vps);
+        rs_avp_free(&m_vps);
 }
 
 bool
@@ -78,7 +91,7 @@ gss_eap_radius_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *ma
     radius = static_cast<const gss_eap_radius_attr_provider *>(ctx);
 
     if (radius->m_vps != NULL)
-        m_vps = copyAvps(const_cast<VALUE_PAIR *>(radius->getAvps()));
+        m_vps = copyAvps(radius->getAvps());
 
     m_authenticated = radius->m_authenticated;
 
@@ -100,7 +113,7 @@ gss_eap_radius_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager
                 return false;
 
             /* We assume libradsec validated this for us */
-            GSSEAP_ASSERT(pairfind(m_vps, PW_MESSAGE_AUTHENTICATOR) != NULL);
+            GSSEAP_ASSERT(rs_avp_find(m_vps, PW_MESSAGE_AUTHENTICATOR, 0) != NULL);
             m_authenticated = true;
         }
     }
@@ -109,12 +122,14 @@ gss_eap_radius_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager
 }
 
 static bool
-alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
+alreadyAddedAttributeP(std::vector <gss_eap_attrid> &attrs,
+                       gss_eap_attrid &attrid)
 {
-    for (std::vector<std::string>::const_iterator a = attrs.begin();
+    for (std::vector<gss_eap_attrid>::const_iterator a = attrs.begin();
          a != attrs.end();
          ++a) {
-        if (strcmp(vp->name, (*a).c_str()) == 0)
+        if (attrid.first == (*a).first &&
+            attrid.second == (*a).second)
             return true;
     }
 
@@ -122,13 +137,13 @@ alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
 }
 
 static bool
-isSecretAttributeP(uint16_t attrid, uint16_t vendor)
+isSecretAttributeP(const gss_eap_attrid &attrid)
 {
     bool bSecretAttribute = false;
 
-    switch (vendor) {
-    case VENDORPEC_MS:
-        switch (attrid) {
+    switch (attrid.first) {
+    case VENDORPEC_MICROSOFT:
+        switch (attrid.second) {
         case PW_MS_MPPE_SEND_KEY:
         case PW_MS_MPPE_RECV_KEY:
             bSecretAttribute = true;
@@ -144,27 +159,35 @@ isSecretAttributeP(uint16_t attrid, uint16_t vendor)
 }
 
 static bool
-isSecretAttributeP(uint32_t attribute)
+isSecretAttributeP(rs_const_avp *vp)
 {
-    return isSecretAttributeP(ATTRID(attribute), VENDOR(attribute));
+    return isSecretAttributeP(avpToAttrId(vp));
 }
 
 static bool
-isInternalAttributeP(uint16_t attrid, uint16_t vendor)
+isInternalAttributeP(const gss_eap_attrid &attrid)
 {
     bool bInternalAttribute = false;
 
     /* should have been filtered */
-    GSSEAP_ASSERT(!isSecretAttributeP(attrid, vendor));
+    GSSEAP_ASSERT(!isSecretAttributeP(attrid));
 
-    switch (vendor) {
+    switch (attrid.first) {
     case VENDORPEC_UKERNA:
-        switch (attrid) {
+        switch (attrid.second) {
+        case PW_SAML_AAA_ASSERTION:
+            bInternalAttribute = true;
+            break;
+        default:
+            break;
+        }
+        break;
+    case 0:
+        switch (attrid.second) {
         case PW_GSS_ACCEPTOR_SERVICE_NAME:
         case PW_GSS_ACCEPTOR_HOST_NAME:
-        case PW_GSS_ACCEPTOR_SERVICE_SPECIFIC:
+        case PW_GSS_ACCEPTOR_SERVICE_SPECIFICS:
         case PW_GSS_ACCEPTOR_REALM_NAME:
-        case PW_SAML_AAA_ASSERTION:
             bInternalAttribute = true;
             break;
         default:
@@ -179,48 +202,42 @@ isInternalAttributeP(uint16_t attrid, uint16_t vendor)
 }
 
 static bool
-isInternalAttributeP(uint32_t attribute)
+isInternalAttributeP(rs_const_avp *vp)
 {
-    return isInternalAttributeP(ATTRID(attribute), VENDOR(attribute));
+    return isInternalAttributeP(avpToAttrId(vp));
 }
 
 static bool
-isFragmentedAttributeP(uint16_t attrid, uint16_t vendor)
+isFragmentedAttributeP(const gss_eap_attrid &attrid)
 {
     /* A bit of a hack for the PAC for now. Should be configurable. */
-    return (vendor == VENDORPEC_UKERNA) &&
-        !isInternalAttributeP(attrid, vendor);
-}
-
-static bool
-isFragmentedAttributeP(uint32_t attribute)
-{
-    return isFragmentedAttributeP(ATTRID(attribute), VENDOR(attribute));
+    return (attrid.first == VENDORPEC_UKERNA) &&
+        !isInternalAttributeP(attrid);
 }
 
 /*
  * Copy AVP list, same as paircopy except it filters out attributes
  * containing keys.
  */
-static VALUE_PAIR *
-copyAvps(const VALUE_PAIR *src)
+static rs_avp *
+copyAvps(rs_const_avp *src)
 {
-    const VALUE_PAIR *vp;
-    VALUE_PAIR *dst = NULL, **pDst = &dst;
+    rs_const_avp *vp;
+    rs_avp *dst = NULL;
 
-    for (vp = src; vp != NULL; vp = vp->next) {
-        VALUE_PAIR *vpcopy;
+    for (vp = src; vp != NULL; vp = rs_avp_next_const(vp)) {
+        rs_avp *vpcopy;
 
-        if (isSecretAttributeP(vp->attribute))
+        if (isSecretAttributeP(vp))
             continue;
 
-        vpcopy = paircopyvp(vp);
+        vpcopy = rs_avp_dup(vp);
         if (vpcopy == NULL) {
-            pairfree(&dst);
+            rs_avp_free(&dst);
             throw std::bad_alloc();
         }
-        *pDst = vpcopy;
-        pDst = &vpcopy->next;
+
+        rs_avp_append(&dst, vpcopy);
      }
 
     return dst;
@@ -230,68 +247,78 @@ bool
 gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
                                                 void *data) const
 {
-    VALUE_PAIR *vp;
-    std::vector <std::string> seen;
+    rs_avp *vp;
+    std::vector <gss_eap_attrid> seen;
 
-    for (vp = m_vps; vp != NULL; vp = vp->next) {
-        gss_buffer_desc attribute;
-        char attrid[64];
+    for (vp = m_vps; vp != NULL; vp = rs_avp_next(vp)) {
+        gss_buffer_desc desc;
+        gss_eap_attrid attrid;
+        char buf[64];
 
         /* Don't advertise attributes that are internal to the GSS-EAP mechanism */
-        if (isInternalAttributeP(vp->attribute))
+        if (isInternalAttributeP(vp))
             continue;
 
-        if (alreadyAddedAttributeP(seen, vp))
+        rs_avp_attrid(vp, &attrid.second, &attrid.first);
+
+        if (alreadyAddedAttributeP(seen, attrid))
             continue;
 
-        snprintf(attrid, sizeof(attrid), "%s%d",
-            (char *)radiusUrnPrefix.value, vp->attribute);
+        if (rs_attr_display_name(attrid.second, attrid.first,
+                                 buf, sizeof(buf), TRUE) != RSE_OK ||
+            strncmp(buf, "Attr-", 5) != 0)
+            continue;
 
-        attribute.value = attrid;
-        attribute.length = strlen(attrid);
+        desc.value = &buf[5];
+        desc.length = strlen((char *)desc.value);
 
-        if (!addAttribute(m_manager, this, &attribute, data))
+        if (!addAttribute(m_manager, this, &desc, data))
             return false;
 
-        seen.push_back(std::string(vp->name));
+        seen.push_back(attrid);
     }
 
     return true;
 }
 
-uint32_t
-getAttributeId(const gss_buffer_t attr)
+static bool
+getAttributeId(const gss_buffer_t desc,
+               gss_eap_attrid *attrid)
 {
-    OM_uint32 tmpMinor;
-    gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
-    DICT_ATTR *da;
-    char *s;
-    uint32_t attrid = 0;
+    char *strAttr, *s;
+    int canon, code;
 
-    if (attr->length < radiusUrnPrefix.length ||
-        memcmp(attr->value, radiusUrnPrefix.value, radiusUrnPrefix.length) != 0)
-        return 0;
+    if (desc->length == 0)
+        return false;
+
+    canon = isdigit(*(char *)desc->value);
 
     /* need to duplicate because attr may not be NUL terminated */
-    duplicateBuffer(*attr, &strAttr);
-    s = (char *)strAttr.value + radiusUrnPrefix.length;
+    strAttr = (char *)GSSEAP_MALLOC((canon ? 5 : 0) + desc->length + 1);
+    if (strAttr == NULL)
+        throw new std::bad_alloc();
 
-    if (isdigit(*s)) {
-        attrid = strtoul(s, NULL, 10);
-    } else {
-        da = dict_attrbyname(s);
-        if (da != NULL)
-            attrid = da->attr;
+    s = strAttr;
+
+    if (canon) {
+        memcpy(s, "Attr-", 5);
+        s += 5;
     }
 
-    gss_release_buffer(&tmpMinor, &strAttr);
+    memcpy(s, desc->value, desc->length);
+    s += desc->length;
+    *s = '\0';
 
-    return attrid;
+    code = rs_attr_parse_name(strAttr, &attrid->second, &attrid->first);
+
+    GSSEAP_FREE(strAttr);
+
+    return (code == RSE_OK);
 }
 
 bool
 gss_eap_radius_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
-                                           uint32_t attrid,
+                                           const gss_eap_attrid &attrid,
                                            const gss_buffer_t value)
 {
     OM_uint32 major = GSS_S_UNAVAILABLE, minor;
@@ -300,9 +327,7 @@ gss_eap_radius_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
         !isInternalAttributeP(attrid)) {
         deleteAttribute(attrid);
 
-        major = gssEapRadiusAddAvp(&minor, &m_vps,
-                                   ATTRID(attrid), VENDOR(attrid), 
-                                   value);
+        major = gssEapRadiusAddAvp(&minor, &m_vps, attrid, value);
     }
 
     return !GSS_ERROR(major);
@@ -313,32 +338,31 @@ gss_eap_radius_attr_provider::setAttribute(int complete,
                                            const gss_buffer_t attr,
                                            const gss_buffer_t value)
 {
-    uint32_t attrid = getAttributeId(attr);
+    gss_eap_attrid attrid;
 
-    if (!attrid)
+    if (!getAttributeId(attr, &attrid))
         return false;
 
     return setAttribute(complete, attrid, value);
 }
 
 bool
-gss_eap_radius_attr_provider::deleteAttribute(uint32_t attrid)
+gss_eap_radius_attr_provider::deleteAttribute(const gss_eap_attrid &attrid)
 {
-    if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid) ||
-        pairfind(m_vps, attrid) == NULL)
+    if (isSecretAttributeP(attrid) ||
+        isInternalAttributeP(attrid) ||
+        rs_avp_find(m_vps, attrid.second, attrid.first) == NULL)
         return false;
 
-    pairdelete(&m_vps, attrid);
-
-    return true;
+    return (rs_avp_delete(&m_vps, attrid.second, attrid.first) == RSE_OK);
 }
 
 bool
 gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t attr)
 {
-    uint32_t attrid = getAttributeId(attr);
+    gss_eap_attrid attrid;
 
-    if (!attrid)
+    if (!getAttributeId(attr, &attrid))
         return false;
 
     return deleteAttribute(attrid);
@@ -352,25 +376,25 @@ gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr,
                                            gss_buffer_t display_value,
                                            int *more) const
 {
-    uint32_t attrid;
+    gss_eap_attrid attrid;
 
-    attrid = getAttributeId(attr);
-    if (!attrid)
+    if (!getAttributeId(attr, &attrid))
         return false;
 
-    return getAttribute(attrid, authenticated, complete,
+    return getAttribute(attrid,
+                        authenticated, complete,
                         value, display_value, more);
 }
 
 bool
-gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
+gss_eap_radius_attr_provider::getAttribute(const gss_eap_attrid &attrid,
                                            int *authenticated,
                                            int *complete,
                                            gss_buffer_t value,
                                            gss_buffer_t display_value,
                                            int *more) const
 {
-    VALUE_PAIR *vp;
+    rs_const_avp *vp;
     int i = *more, count = 0;
 
     *more = 0;
@@ -378,7 +402,8 @@ gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
     if (i == -1)
         i = 0;
 
-    if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid)) {
+    if (isSecretAttributeP(attrid) ||
+        isInternalAttributeP(attrid)) {
         return false;
     } else if (isFragmentedAttributeP(attrid)) {
         return getFragmentedAttribute(attrid,
@@ -387,11 +412,11 @@ gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
                                       value);
     }
 
-    for (vp = pairfind(m_vps, attrid);
+    for (vp = rs_avp_find_const(m_vps, attrid.second, attrid.first);
          vp != NULL;
-         vp = pairfind(vp->next, attrid)) {
+         vp = rs_avp_find_const(rs_avp_next_const(vp), attrid.second, attrid.first)) {
         if (count++ == i) {
-            if (pairfind(vp->next, attrid) != NULL)
+            if (rs_avp_find_const(rs_avp_next_const(vp), attrid.second, attrid.first) != NULL)
                 *more = count;
             break;
         }
@@ -403,19 +428,20 @@ gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
     if (value != GSS_C_NO_BUFFER) {
         gss_buffer_desc valueBuf;
 
-        valueBuf.value = (void *)vp->vp_octets;
-        valueBuf.length = vp->length;
+        rs_avp_octets_value_byref((rs_avp *)vp,
+                                  (unsigned char **)&valueBuf.value,
+                                  &valueBuf.length);
 
         duplicateBuffer(valueBuf, value);
     }
 
     if (display_value != GSS_C_NO_BUFFER &&
-        vp->type != PW_TYPE_OCTETS) {
-        char displayString[MAX_STRING_LEN];
+        !rs_avp_is_octets(vp)) {
+        char displayString[RS_MAX_STRING_LEN];
         gss_buffer_desc displayBuf;
 
-        displayBuf.length = vp_prints_value(displayString,
-                                            sizeof(displayString), vp, 0);
+        displayBuf.length = rs_avp_display_value(vp, displayString,
+                                                 sizeof(displayString));
         displayBuf.value = (void *)displayString;
 
         duplicateBuffer(displayBuf, display_value);
@@ -430,15 +456,14 @@ gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
 }
 
 bool
-gss_eap_radius_attr_provider::getFragmentedAttribute(uint16_t attribute,
-                                                     uint16_t vendor,
+gss_eap_radius_attr_provider::getFragmentedAttribute(const gss_eap_attrid &attrid,
                                                      int *authenticated,
                                                      int *complete,
                                                      gss_buffer_t value) const
 {
     OM_uint32 major, minor;
 
-    major = gssEapRadiusGetAvp(&minor, m_vps, attribute, vendor, value, TRUE);
+    major = gssEapRadiusGetAvp(&minor, m_vps, attrid, value, TRUE);
 
     if (authenticated != NULL)
         *authenticated = m_authenticated;
@@ -448,31 +473,6 @@ gss_eap_radius_attr_provider::getFragmentedAttribute(uint16_t attribute,
     return !GSS_ERROR(major);
 }
 
-bool
-gss_eap_radius_attr_provider::getFragmentedAttribute(uint32_t attrid,
-                                                     int *authenticated,
-                                                     int *complete,
-                                                     gss_buffer_t value) const
-{
-    return getFragmentedAttribute(ATTRID(attrid), VENDOR(attrid),
-                                  authenticated, complete, value);
-}
-
-bool
-gss_eap_radius_attr_provider::getAttribute(uint16_t attribute,
-                                           uint16_t vendor,
-                                           int *authenticated,
-                                           int *complete,
-                                           gss_buffer_t value,
-                                           gss_buffer_t display_value,
-                                           int *more) const
-{
-
-    return getAttribute(VENDORATTR(attribute, vendor),
-                        authenticated, complete,
-                        value, display_value, more);
-}
-
 gss_any_t
 gss_eap_radius_attr_provider::mapToAny(int authenticated,
                                        gss_buffer_t type_id GSSEAP_UNUSED) const
@@ -487,8 +487,8 @@ void
 gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
                                                     gss_any_t input) const
 {
-    VALUE_PAIR *vp = (VALUE_PAIR *)input;
-    pairfree(&vp);
+    rs_avp *vp = (rs_avp *)input;
+    rs_avp_free(&vp);
 }
 
 bool
@@ -511,38 +511,35 @@ gss_eap_radius_attr_provider::createAttrContext(void)
     return new gss_eap_radius_attr_provider;
 }
 
-OM_uint32
+static OM_uint32
 gssEapRadiusAddAvp(OM_uint32 *minor,
-                   VALUE_PAIR **vps,
-                   uint16_t attribute,
-                   uint16_t vendor,
+                   rs_avp **vps,
+                   const gss_eap_attrid &attrid,
                    const gss_buffer_t buffer)
 {
-    uint32_t attrid = VENDORATTR(vendor, attribute);
     unsigned char *p = (unsigned char *)buffer->value;
     size_t remain = buffer->length;
 
     do {
-        VALUE_PAIR *vp;
+        rs_avp *vp;
         size_t n = remain;
 
         /*
          * There's an extra byte of padding; RADIUS AVPs can only
          * be 253 octets.
          */
-        if (n >= MAX_STRING_LEN)
-            n = MAX_STRING_LEN - 1;
+        if (n >= RS_MAX_STRING_LEN)
+            n = RS_MAX_STRING_LEN - 1;
 
-        vp = paircreate(attrid, PW_TYPE_OCTETS);
+        vp = rs_avp_alloc(attrid.second, attrid.first);
         if (vp == NULL) {
             *minor = ENOMEM;
             return GSS_S_FAILURE;
         }
 
-        memcpy(vp->vp_octets, p, n);
-        vp->length = n;
+        rs_avp_octets_set(vp, p, n);
 
-        pairadd(vps, vp);
+        rs_avp_append(vps, vp);
 
         p += n;
         remain -= n;
@@ -552,15 +549,34 @@ gssEapRadiusAddAvp(OM_uint32 *minor,
 }
 
 OM_uint32
-gssEapRadiusGetRawAvp(OM_uint32 *minor,
-                      VALUE_PAIR *vps,
-                      uint16_t attribute,
-                      uint16_t vendor,
-                      VALUE_PAIR **vp)
+gssEapRadiusAddAvp(OM_uint32 *minor,
+                   struct rs_packet *pkt,
+                   unsigned int attribute,
+                   unsigned int vendor,
+                   const gss_buffer_t buffer)
 {
-    uint32_t attr = VENDORATTR(vendor, attribute);
+    gss_eap_attrid attrid(vendor, attribute);
+    int code;
+
+    code = rs_packet_append_avp(pkt, attrid.second, attrid.first,
+                                buffer->value, buffer->length);
+    if (code != RSE_OK) {
+        *minor = RS_MAP_ERROR(code);
+        return GSS_S_FAILURE;
+    }
 
-    *vp = pairfind(vps, attr);
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapRadiusGetRawAvp(OM_uint32 *minor,
+                      rs_const_avp *vps,
+                      unsigned int attribute,
+                      unsigned int vendor,
+                      rs_const_avp **vp)
+{
+    *vp = rs_avp_find_const(vps, attribute, vendor);
     if (*vp == NULL) {
         *minor = GSSEAP_NO_SUCH_ATTR;
         return GSS_S_UNAVAILABLE;
@@ -569,33 +585,32 @@ gssEapRadiusGetRawAvp(OM_uint32 *minor,
     return GSS_S_COMPLETE;
 }
 
-OM_uint32
+static OM_uint32
 gssEapRadiusGetAvp(OM_uint32 *minor,
-                   VALUE_PAIR *vps,
-                   uint16_t attribute,
-                   uint16_t vendor,
+                   rs_avp *vps,
+                   const gss_eap_attrid &attrid,
                    gss_buffer_t buffer,
                    int concat)
 {
-    VALUE_PAIR *vp;
-    unsigned char *p;
-    uint32_t attr = VENDORATTR(vendor, attribute);
+    rs_const_avp *vp;
+    int err;
 
     if (buffer != GSS_C_NO_BUFFER) {
         buffer->length = 0;
         buffer->value = NULL;
     }
 
-    vp = pairfind(vps, attr);
+    vp = rs_avp_find_const(vps, attrid.second, attrid.first);
     if (vp == NULL) {
         *minor = GSSEAP_NO_SUCH_ATTR;
         return GSS_S_UNAVAILABLE;
     }
 
     if (buffer != GSS_C_NO_BUFFER) {
-        do {
-            buffer->length += vp->length;
-        } while (concat && (vp = pairfind(vp->next, attr)) != NULL);
+        if (concat)
+            rs_avp_fragmented_value(vp, NULL, &buffer->length);
+        else
+            buffer->length = rs_avp_length(vp);
 
         buffer->value = GSSEAP_MALLOC(buffer->length);
         if (buffer->value == NULL) {
@@ -603,13 +618,14 @@ gssEapRadiusGetAvp(OM_uint32 *minor,
             return GSS_S_FAILURE;
         }
 
-        p = (unsigned char *)buffer->value;
+        if (concat)
+            err = rs_avp_fragmented_value(vp, (unsigned char *)buffer->value, &buffer->length);
+        else
+            err = rs_avp_octets_value(vp, (unsigned char *)buffer->value, &buffer->length);
 
-        for (vp = pairfind(vps, attr);
-             concat && vp != NULL;
-             vp = pairfind(vp->next, attr)) {
-            memcpy(p, vp->vp_octets, vp->length);
-            p += vp->length;
+        if (err != 0) {
+            *minor = RS_MAP_ERROR(err);
+            return GSS_S_FAILURE;
         }
     }
 
@@ -618,10 +634,26 @@ gssEapRadiusGetAvp(OM_uint32 *minor,
 }
 
 OM_uint32
+gssEapRadiusGetAvp(OM_uint32 *minor,
+                   struct rs_packet *pkt,
+                   unsigned int attribute,
+                   unsigned int vendor,
+                   gss_buffer_t buffer,
+                   int concat)
+{
+    rs_avp **vps;
+    gss_eap_attrid attrid(vendor, attribute);
+
+    rs_packet_avps(pkt, &vps);
+
+    return gssEapRadiusGetAvp(minor, *vps, attrid, buffer, concat);
+}
+
+OM_uint32
 gssEapRadiusFreeAvps(OM_uint32 *minor,
-                     VALUE_PAIR **vps)
+                     rs_avp **vps)
 {
-    pairfree(vps);
+    rs_avp_free(vps);
     *minor = 0;
     return GSS_S_COMPLETE;
 }
@@ -647,25 +679,28 @@ gssEapRadiusAttrProviderFinalize(OM_uint32 *minor)
 }
 
 static JSONObject
-avpToJson(const VALUE_PAIR *vp)
+avpToJson(rs_const_avp *vp)
 {
     JSONObject obj;
+    gss_eap_attrid attrid;
 
-    GSSEAP_ASSERT(vp->length <= MAX_STRING_LEN);
+    GSSEAP_ASSERT(rs_avp_length(vp) <= RS_MAX_STRING_LEN);
 
-    switch (vp->type) {
-    case PW_TYPE_INTEGER:
-    case PW_TYPE_IPADDR:
-    case PW_TYPE_DATE:
-        obj.set("value", vp->lvalue);
+    switch (rs_avp_typeof(vp)) {
+    case RS_TYPE_INTEGER:
+        obj.set("value", rs_avp_integer_value(vp));
+        break;
+    case RS_TYPE_DATE:
+        obj.set("value", rs_avp_date_value(vp));
         break;
-    case PW_TYPE_STRING:
-        obj.set("value", vp->vp_strvalue);
+    case RS_TYPE_STRING:
+        obj.set("value", rs_avp_string_value(vp));
         break;
     default: {
         char *b64;
 
-        if (base64Encode(vp->vp_octets, vp->length, &b64) < 0)
+        if (base64Encode(rs_avp_octets_value_const_ptr(vp),
+                         rs_avp_length(vp), &b64) < 0)
             throw std::bad_alloc();
 
         obj.set("value", b64);
@@ -674,62 +709,65 @@ avpToJson(const VALUE_PAIR *vp)
     }
     }
 
-    obj.set("type", vp->attribute);
+    attrid = avpToAttrId(vp);
+
+    obj.set("type", attrid.second);
+    if (attrid.first != 0)
+        obj.set("vendor", attrid.first);
 
     return obj;
 }
 
 static bool
-jsonToAvp(VALUE_PAIR **pVp, JSONObject &obj)
+jsonToAvp(rs_avp **pVp, JSONObject &obj)
 {
-    VALUE_PAIR *vp = NULL;
-    DICT_ATTR *da;
-    uint32_t attrid;
+    rs_avp *vp = NULL;
+    gss_eap_attrid attrid;
 
     JSONObject type = obj["type"];
+    JSONObject vendor = obj["vendor"];
     JSONObject value = obj["value"];
 
     if (!type.isInteger())
         goto fail;
+    attrid.second = type.integer();
 
-    attrid = type.integer();
-    da = dict_attrbyvalue(attrid);
-    if (da != NULL) {
-        vp = pairalloc(da);
+    if (!vendor.isNull()) {
+        if (!vendor.isInteger())
+            goto fail;
+        attrid.first = vendor.integer();
     } else {
-        int type = base64Valid(value.string()) ?
-            PW_TYPE_OCTETS : PW_TYPE_STRING;
-        vp = paircreate(attrid, type);
+        attrid.first = 0;
     }
+
+    vp = rs_avp_alloc(attrid.second, attrid.first);
     if (vp == NULL)
         throw std::bad_alloc();
 
-    switch (vp->type) {
-    case PW_TYPE_INTEGER:
-    case PW_TYPE_IPADDR:
-    case PW_TYPE_DATE:
+    switch (rs_avp_typeof(vp)) {
+    case RS_TYPE_INTEGER:
+    case RS_TYPE_IPADDR:
+    case RS_TYPE_DATE:
         if (!value.isInteger())
             goto fail;
 
-        vp->length = 4;
-        vp->lvalue = value.integer();
+        if (rs_avp_integer_set(vp, value.integer()) != RSE_OK)
+            goto fail;
+
         break;
-    case PW_TYPE_STRING: {
+    case RS_TYPE_STRING: {
         if (!value.isString())
             goto fail;
 
-        const char *str = value.string();
-        size_t len = strlen(str);
-
-        if (len >= MAX_STRING_LEN)
+        if (rs_avp_string_set(vp, value.string()) != RSE_OK)
             goto fail;
 
-        vp->length = len;
-        memcpy(vp->vp_strvalue, str, len + 1);
         break;
     }
-    case PW_TYPE_OCTETS:
+    case RS_TYPE_OCTETS:
     default: {
+        unsigned char buf[RS_MAX_STRING_LEN];
+
         if (!value.isString())
             goto fail;
 
@@ -737,14 +775,16 @@ jsonToAvp(VALUE_PAIR **pVp, JSONObject &obj)
         ssize_t len = strlen(str);
 
         /* this optimization requires base64Decode only understand packed encoding */
-        if (len >= BASE64_EXPAND(MAX_STRING_LEN))
+        if (len >= BASE64_EXPAND(RS_MAX_STRING_LEN))
             goto fail;
 
-        len = base64Decode(str, vp->vp_octets);
+        len = base64Decode(str, buf);
         if (len < 0)
             goto fail;
 
-        vp->length = len;
+        if (rs_avp_octets_set(vp, buf, len) != RSE_OK)
+            goto fail;
+
         break;
     }
     }
@@ -755,7 +795,7 @@ jsonToAvp(VALUE_PAIR **pVp, JSONObject &obj)
 
 fail:
     if (vp != NULL)
-        pairbasicfree(vp);
+        rs_avp_free(&vp);
     *pVp = NULL;
     return false;
 }
@@ -770,8 +810,6 @@ bool
 gss_eap_radius_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
                                                  JSONObject &obj)
 {
-    VALUE_PAIR **pNext = &m_vps;
-
     if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
         return false;
 
@@ -780,13 +818,12 @@ gss_eap_radius_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
 
     for (size_t i = 0; i < nelems; i++) {
         JSONObject attr = attrs[i];
-        VALUE_PAIR *vp;
+        rs_avp *vp;
 
         if (!jsonToAvp(&vp, attr))
             return false;
 
-        *pNext = vp;
-        pNext = &vp->next;
+        rs_avp_append(&m_vps, vp);
     }
 
     m_authenticated = obj["authenticated"].integer() ? true : false;
@@ -797,7 +834,7 @@ gss_eap_radius_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
 const char *
 gss_eap_radius_attr_provider::prefix(void) const
 {
-    return "urn:ietf:params:gss-eap:radius-avp";
+    return "urn:ietf:params:gss:radius-attribute";
 }
 
 JSONObject
@@ -805,7 +842,7 @@ gss_eap_radius_attr_provider::jsonRepresentation(void) const
 {
     JSONObject obj, attrs = JSONObject::array();
 
-    for (VALUE_PAIR *vp = m_vps; vp != NULL; vp = vp->next) {
+    for (rs_avp *vp = m_vps; vp != NULL; vp = rs_avp_next(vp)) {
         JSONObject attr = avpToJson(vp);
         attrs.append(attr);
     }
@@ -820,13 +857,18 @@ gss_eap_radius_attr_provider::jsonRepresentation(void) const
 time_t
 gss_eap_radius_attr_provider::getExpiryTime(void) const
 {
-    VALUE_PAIR *vp;
+    rs_const_avp *vp;
+    uint32_t value;
+
+    vp = rs_avp_find(m_vps, PW_SESSION_TIMEOUT, 0);
+    if (vp == NULL)
+        return 0;
 
-    vp = pairfind(m_vps, PW_SESSION_TIMEOUT);
-    if (vp == NULL || vp->lvalue == 0)
+    value = rs_avp_integer_value(vp);
+    if (value == 0)
         return 0;
 
-    return time(NULL) + vp->lvalue;
+    return time(NULL) + value;
 }
 
 OM_uint32
@@ -844,7 +886,7 @@ gssEapRadiusMapError(OM_uint32 *minor,
         return GSS_S_COMPLETE;
     }
 
-    *minor = ERROR_TABLE_BASE_rse + code;
+    *minor = RS_MAP_ERROR(code);
 
     gssEapSaveStatusInfo(*minor, "%s", rs_err_msg(err));
     rs_err_free(err);
@@ -885,11 +927,6 @@ gssEapCreateRadiusContext(OM_uint32 *minor,
         goto fail;
     }
 
-    if (rs_context_init_freeradius_dict(radContext, NULL) != 0) {
-        err = rs_err_ctx_pop(radContext);
-        goto fail;
-    }
-
     *pRadContext = radContext;
 
     *minor = 0;
index 8c34167..d4f86ec 100644 (file)
 
 #ifdef __cplusplus
 
+typedef std::pair <unsigned int, unsigned int> gss_eap_attrid;
 #ifdef GSSEAP_ENABLE_ACCEPTOR
 
+
 struct gss_eap_radius_attr_provider : gss_eap_attr_provider {
 public:
     gss_eap_radius_attr_provider(void);
@@ -74,30 +76,18 @@ public:
                            JSONObject &obj);
     JSONObject jsonRepresentation(void) const;
 
-    bool getAttribute(uint32_t attribute,
-                      int *authenticated,
-                      int *complete,
-                      gss_buffer_t value,
-                      gss_buffer_t display_value,
-                      int *more) const;
-    bool getAttribute(uint16_t attribute,
-                      uint16_t vendor,
+    bool getAttribute(const gss_eap_attrid &attrid,
                       int *authenticated,
                       int *complete,
                       gss_buffer_t value,
                       gss_buffer_t display_value,
                       int *more) const;
     bool setAttribute(int complete,
-                      uint32_t attribute,
+                      const gss_eap_attrid &attrid,
                       const gss_buffer_t value);
-    bool deleteAttribute(uint32_t attribute);
+    bool deleteAttribute(const gss_eap_attrid &attrid);
 
-    bool getFragmentedAttribute(uint16_t attribute,
-                                uint16_t vendor,
-                                int *authenticated,
-                                int *complete,
-                                gss_buffer_t value) const;
-    bool getFragmentedAttribute(uint32_t attrid,
+    bool getFragmentedAttribute(const gss_eap_attrid &attrid,
                                 int *authenticated,
                                 int *complete,
                                 gss_buffer_t value) const;
@@ -112,11 +102,11 @@ public:
     static gss_eap_attr_provider *createAttrContext(void);
 
 private:
-    const VALUE_PAIR *getAvps(void) const {
+    rs_const_avp *getAvps(void) const {
         return m_vps;
     }
 
-    VALUE_PAIR *m_vps;
+    rs_avp *m_vps;
     bool m_authenticated;
 };
 
@@ -130,28 +120,28 @@ extern "C" {
 
 OM_uint32
 gssEapRadiusAddAvp(OM_uint32 *minor,
-                   VALUE_PAIR **vp,
-                   uint16_t type,
-                   uint16_t vendor,
+                   struct rs_packet *pkt,
+                   unsigned int type,
+                   unsigned int vendor,
                    const gss_buffer_t buffer);
 
 OM_uint32
 gssEapRadiusGetAvp(OM_uint32 *minor,
-                   VALUE_PAIR *vps,
-                   uint16_t type,
-                   uint16_t vendor,
+                   struct rs_packet *pkt,
+                   unsigned int type,
+                   unsigned int vendor,
                    gss_buffer_t buffer,
                    int concat);
 
 OM_uint32
 gssEapRadiusGetRawAvp(OM_uint32 *minor,
-                      VALUE_PAIR *vps,
-                      uint16_t type,
-                      uint16_t vendor,
-                      VALUE_PAIR **vp);
+                      rs_const_avp *vps,
+                      unsigned int type,
+                      unsigned int vendor,
+                      rs_const_avp **vp);
 OM_uint32
 gssEapRadiusFreeAvps(OM_uint32 *minor,
-                     VALUE_PAIR **vps);
+                     rs_avp **vps);
 
 OM_uint32 gssEapRadiusAttrProviderInit(OM_uint32 *minor);
 OM_uint32 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor);
@@ -180,20 +170,6 @@ gssEapRadiusAddAttr(OM_uint32 *minor,
 /* This really needs to be a function call on Windows */
 #define RS_CONFIG_FILE      SYSCONFDIR "/radsec.conf"
 
-#define VENDORPEC_MS                        311 /* RFC 2548 */
-
-#define PW_MS_MPPE_SEND_KEY                 16
-#define PW_MS_MPPE_RECV_KEY                 17
-
-#define VENDORPEC_UKERNA                    25622
-
-#define PW_GSS_ACCEPTOR_SERVICE_NAME        128
-#define PW_GSS_ACCEPTOR_HOST_NAME           129
-#define PW_GSS_ACCEPTOR_SERVICE_SPECIFIC    130
-#define PW_GSS_ACCEPTOR_REALM_NAME          131
-#define PW_SAML_AAA_ASSERTION               132
-#define PW_MS_WINDOWS_AUTH_DATA             133
-
 #ifdef __cplusplus
 }
 #endif
index 50011ca..40e3de1 100644 (file)
@@ -214,6 +214,11 @@ gssEapMakeReauthCreds(OM_uint32 *minor,
     credBuf->length = 0;
     credBuf->value = NULL;
 
+    if (ctx->acceptorName == GSS_C_NO_NAME) {
+        *minor = GSSEAP_NO_ACCEPTOR_NAME;
+        return GSS_S_UNAVAILABLE;
+    }
+
     GSSEAP_KRB_INIT(&krbContext);
 
     code = getAcceptorKey(krbContext, ctx, cred, &server, &acceptorKey);
@@ -635,7 +640,7 @@ cleanup:
 
 #ifndef HAVE_HEIMDAL_VERSION
 static gss_buffer_desc radiusAvpKrbAttr = {
-    sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp"
+    sizeof("urn:authdata-aaa-radius") - 1, "urn:authdata-aaa-radius"
 };
 #endif
 
index ce7582e..bf82a57 100644 (file)
@@ -103,6 +103,7 @@ gss_eap_saml_assertion_provider::initWithGssContext(const gss_eap_attr_ctx *mana
     gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
     int authenticated, complete;
     OM_uint32 minor;
+    gss_eap_attrid attrid(VENDORPEC_UKERNA, PW_SAML_AAA_ASSERTION);
 
     GSSEAP_ASSERT(m_assertion == NULL);
 
@@ -115,9 +116,7 @@ gss_eap_saml_assertion_provider::initWithGssContext(const gss_eap_attr_ctx *mana
     radius = static_cast<const gss_eap_radius_attr_provider *>
         (m_manager->getProvider(ATTR_TYPE_RADIUS));
     if (radius != NULL &&
-        radius->getFragmentedAttribute(PW_SAML_AAA_ASSERTION,
-                                       VENDORPEC_UKERNA,
-                                       &authenticated, &complete, &value)) {
+        radius->getFragmentedAttribute(attrid, &authenticated, &complete, &value)) {
         setAssertion(&value, authenticated);
         gss_release_buffer(&minor, &value);
     } else {
@@ -317,7 +316,7 @@ gss_eap_saml_assertion_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSE
 const char *
 gss_eap_saml_assertion_provider::prefix(void) const
 {
-    return "urn:ietf:params:gss-eap:saml-aaa-assertion";
+    return "urn:ietf:params:gss:federated-saml-assertion";
 }
 
 bool
@@ -414,7 +413,7 @@ gss_eap_saml_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAtt
      *   Each attribute carried in the assertion SHOULD also be a GSS name
      *   attribute.  The name of this attribute has three parts, all separated
      *   by an ASCII space character.  The first part is
-     *   urn:ietf:params:gss-eap:saml-attr.  The second part is the URI for
+     *   urn:ietf:params:gss:federated-saml-attribute.  The second part is the URI for
      *   the SAML attribute name format.  The final part is the name of the
      *   SAML attribute.  If the mechanism performs an additional attribute
      *   query, the retrieved attributes SHOULD be GSS-API name attributes
@@ -730,7 +729,7 @@ gss_eap_saml_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UN
 const char *
 gss_eap_saml_attr_provider::prefix(void) const
 {
-    return "urn:ietf:params:gss-eap:saml-attr";
+    return "urn:ietf:params:gss:federated-saml-attribute";
 }
 
 bool
index f8c702b..7b62484 100644 (file)
@@ -163,13 +163,12 @@ gss_eap_shib_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
     const gss_eap_radius_attr_provider *radius;
     int authenticated, complete;
     gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
+    gss_eap_attrid attrid(VENDORPEC_UKERNA, PW_SAML_AAA_ASSERTION);
 
     radius = static_cast<const gss_eap_radius_attr_provider *>
         (m_manager->getProvider(ATTR_TYPE_RADIUS));
     if (radius != NULL &&
-        radius->getFragmentedAttribute(PW_SAML_AAA_ASSERTION,
-                                       VENDORPEC_UKERNA,
-                                       &authenticated, &complete, &value)) {
+        radius->getFragmentedAttribute(attrid, &authenticated, &complete, &value)) {
         string str((char *)value.value, value.length);
         istringstream istream(str);
         DOMDocument *doc = XMLToolingConfig::getConfig().getParser().parse(istream);