#include "gssapiP_eap.h"
static OM_uint32
-gssEapExportPartialContext(OM_uint32 *minor,
+exportPartialRadiusContext(OM_uint32 *minor,
gss_ctx_id_t ctx,
gss_buffer_t token)
{
if (ctx->acceptorCtx.radConn != NULL) {
if (rs_conn_get_current_peer(ctx->acceptorCtx.radConn,
serverBuf, sizeof(serverBuf)) != 0) {
+ #if 0
return gssEapRadiusMapError(minor,
rs_err_conn_pop(ctx->acceptorCtx.radConn));
+ #else
+ serverBuf[0] = '\0'; /* not implemented yet */
+ #endif
}
serverLen = strlen(serverBuf);
}
return major;
}
- static OM_uint32
+ OM_uint32
gssEapExportSecContext(OM_uint32 *minor,
gss_ctx_id_t ctx,
gss_buffer_t token)
if (GSS_ERROR(major))
goto cleanup;
}
+
if (ctx->acceptorName != GSS_C_NO_NAME) {
major = gssEapExportNameInternal(minor, ctx->acceptorName,
&acceptorName,
* The partial context is only transmitted for unestablished acceptor
* contexts.
*/
- if (!CTX_IS_INITIATOR(ctx) &&
- !CTX_IS_ESTABLISHED(ctx) &&
- ((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0)) {
- major = exportPartialRadiusContext(minor, ctx, &partialCtx);
+ if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) &&
+ (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
+ major = gssEapExportPartialContext(minor, ctx, &partialCtx);
if (GSS_ERROR(major))
goto cleanup;
}
length += 4 + acceptorName.length; /* acceptorName.value */
length += 24 + sequenceSize(ctx->seqState); /* seqState */
+ if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx))
+ length += 4 + ctx->conversation.length;
+
if (partialCtx.value != NULL)
length += 4 + partialCtx.length; /* partialCtx.value */
if (GSS_ERROR(major))
goto cleanup;
+ if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx))
+ p = store_buffer(&ctx->conversation, &p, FALSE);
+
if (partialCtx.value != NULL)
p = store_buffer(&partialCtx, p, FALSE);
#define CTX_FLAG_INITIATOR 0x00000001
#define CTX_FLAG_KRB_REAUTH 0x00000002
+#define CTX_FLAG_KRB_REAUTH_SUPPORTED 0x00000004
#define CTX_IS_INITIATOR(ctx) (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
#define kerberosCtx ctxU.kerberos
#endif
} ctxU;
+ gss_buffer_desc conversation;
};
#define TOK_FLAG_SENDER_IS_ACCEPTOR 0x01
#define IS_WIRE_ERROR(err) ((err) > GSSEAP_RESERVED && \
(err) <= GSSEAP_RADIUS_PROT_FAILURE)
+ /* export_sec_context.c */
+ OM_uint32
+ gssEapExportSecContext(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t token);
+
+
#ifdef __cplusplus
}
#endif
TOK_TYPE_ACCEPTOR_CONTEXT = 0x0602, /* acceptor-sent context token */
};
+struct gss_eap_itok_map {
+ OM_uint32 type; /* inner token type */
+ OM_uint32 flag; /* context flag */
+};
+
/* inner token types and flags */
-#define ITOK_TYPE_NONE 0x00000000
-#define ITOK_TYPE_CONTEXT_ERR 0x00000001 /* critical */
-#define ITOK_TYPE_ACCEPTOR_NAME_REQ 0x00000002 /* TBD */
-#define ITOK_TYPE_ACCEPTOR_NAME_RESP 0x00000003 /* TBD */
-#define ITOK_TYPE_EAP_RESP 0x00000004 /* critical, required, if not reauth */
-#define ITOK_TYPE_EAP_REQ 0x00000005 /* critical, required, if not reauth */
-#define ITOK_TYPE_GSS_CHANNEL_BINDINGS 0x00000006 /* critical, required, if not reauth */
-#define ITOK_TYPE_REAUTH_CREDS 0x00000007 /* optional */
-#define ITOK_TYPE_REAUTH_REQ 0x00000008 /* optional */
-#define ITOK_TYPE_REAUTH_RESP 0x00000009 /* optional */
-#define ITOK_TYPE_VERSION_INFO 0x0000000A /* optional */
-#define ITOK_TYPE_VENDOR_INFO 0x0000000B /* optional */
-
-#define ITOK_FLAG_CRITICAL 0x80000000 /* critical, wire flag */
-#define ITOK_FLAG_VERIFIED 0x40000000 /* verified, API flag */
-
-#define ITOK_TYPE_MASK (~(ITOK_FLAG_CRITICAL | ITOK_FLAG_VERIFIED))
+#define ITOK_TYPE_NONE 0x00000000
+#define ITOK_TYPE_CONTEXT_ERR 0x00000001 /* critical */
+#define ITOK_TYPE_ACCEPTOR_NAME_REQ 0x00000002 /* TBD */
+#define ITOK_TYPE_ACCEPTOR_NAME_RESP 0x00000003 /* TBD */
+#define ITOK_TYPE_EAP_RESP 0x00000004 /* critical, required, if not reauth */
+#define ITOK_TYPE_EAP_REQ 0x00000005 /* critical, required, if not reauth */
+#define ITOK_TYPE_GSS_CHANNEL_BINDINGS 0x00000006 /* optional */
+#define ITOK_TYPE_REAUTH_CREDS 0x00000007 /* optional */
+#define ITOK_TYPE_REAUTH_REQ 0x00000008 /* optional */
+#define ITOK_TYPE_REAUTH_RESP 0x00000009 /* optional */
+#define ITOK_TYPE_GSS_FLAGS 0x0000000A /* optional */
+#define ITOK_TYPE_INITIATOR_MIC 0x0000000B /* required */
+#define ITOK_TYPE_ACCEPTOR_MIC 0x0000000C /* required */
+#define ITOK_TYPE_SUPPORTED_ACCEPTOR_EXTS 0x0000000D /* optional */
+#define ITOK_TYPE_SUPPORTED_INITIATOR_EXTS 0x0000000E /* optional */
+
+/* experimental */
+#define ITOK_TYPE_VERSION_INFO 0x00000080 /* optional */
+#define ITOK_TYPE_VENDOR_INFO 0x00000081 /* optional */
+
+#define ITOK_FLAG_CRITICAL 0x80000000 /* critical, wire flag */
+#define ITOK_FLAG_VERIFIED 0x40000000 /* verified, API flag */
+
+#define ITOK_TYPE_MASK (~(ITOK_FLAG_CRITICAL | ITOK_FLAG_VERIFIED))
+
+#define ITOK_HEADER_LENGTH 8 /* type || length */
+
+#define GSSEAP_WIRE_FLAGS_MASK ( GSS_C_MUTUAL_FLAG )
OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
OM_uint32
-gssEapMakeToken(OM_uint32 *minor,
- gss_ctx_id_t ctx,
- const gss_buffer_t innerToken,
- enum gss_eap_token_type tokenType,
- gss_buffer_t outputToken);
+gssEapContextTime(OM_uint32 *minor,
+ gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec);
OM_uint32
-gssEapVerifyToken(OM_uint32 *minor,
- gss_ctx_id_t ctx,
- const gss_buffer_t inputToken,
- enum gss_eap_token_type *tokenType,
- gss_buffer_t innerInputToken);
+gssEapGetConversationMIC(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t convMIC);
OM_uint32
-gssEapContextTime(OM_uint32 *minor,
- gss_ctx_id_t context_handle,
- OM_uint32 *time_rec);
+gssEapVerifyConversationMIC(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ const gss_buffer_t convMIC);
+
+OM_uint32
+gssEapMakeTokenChannelBindings(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_channel_bindings_t userBindings,
+ gss_buffer_t inputToken,
+ gss_channel_bindings_t wireBindings);
/* util_cred.c */
OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred);
gssEapSaslNameToOid(const gss_buffer_t name);
/* util_name.c */
- #define EXPORT_NAME_FLAG_OID 0x1
- #define EXPORT_NAME_FLAG_COMPOSITE 0x2
+ #define EXPORT_NAME_FLAG_OID 0x1
+ #define EXPORT_NAME_FLAG_COMPOSITE 0x2
OM_uint32 gssEapAllocName(OM_uint32 *minor, gss_name_t *pName);
OM_uint32 gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName);
OM_uint32 gssEapExportNameInternal(OM_uint32 *minor,
const gss_name_t name,
gss_buffer_t exportedName,
- unsigned int flags);
+ OM_uint32 flags);
OM_uint32 gssEapImportName(OM_uint32 *minor,
const gss_buffer_t input_name_buffer,
const gss_OID input_name_type,
OM_uint32 gssEapImportNameInternal(OM_uint32 *minor,
const gss_buffer_t input_name_buffer,
gss_name_t *output_name,
- unsigned int flags);
+ OM_uint32 flags);
OM_uint32
gssEapDuplicateName(OM_uint32 *minor,
const gss_name_t input_name,
};
/* state machine flags, set by handler */
-#define SM_FLAG_FORCE_SEND_TOKEN 0x00000001 /* send token even if no inner tokens */
+#define SM_FLAG_SEND_TOKEN 0x00000001 /* exit state machine, send token */
#define SM_FLAG_OUTPUT_TOKEN_CRITICAL 0x00000002 /* output token is critical */
/* state machine flags, set by state machine */
/* util_token.c */
OM_uint32
-gssEapEncodeInnerTokens(OM_uint32 *minor,
- gss_buffer_set_t extensions,
- OM_uint32 *types,
- gss_buffer_t buffer);
-OM_uint32
gssEapDecodeInnerTokens(OM_uint32 *minor,
const gss_buffer_t buffer,
gss_buffer_set_t *pExtensions,
OM_uint32 **pTypes);
+OM_uint32
+gssEapRecordContextTokenHeader(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ enum gss_eap_token_type tokType);
+
+OM_uint32
+gssEapRecordInnerContextToken(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t innerToken,
+ OM_uint32 type);
+
+OM_uint32
+gssEapVerifyContextToken(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ const gss_buffer_t inputToken,
+ enum gss_eap_token_type tokenType,
+ gss_buffer_t innerInputToken);
+
+OM_uint32
+gssEapEncodeSupportedExts(OM_uint32 *minor,
+ OM_uint32 *types,
+ size_t typesCount,
+ gss_buffer_t outputToken);
+
+OM_uint32
+gssEapProcessSupportedExts(OM_uint32 *minor,
+ gss_buffer_t inputToken,
+ struct gss_eap_itok_map *map,
+ size_t mapCount,
+ OM_uint32 *flags);
+
size_t
-tokenSize(const gss_OID_desc *mech, size_t body_size);
+tokenSize(size_t bodySize);
void
-makeTokenHeader(const gss_OID_desc *mech,
- size_t body_size,
- unsigned char **buf,
- enum gss_eap_token_type tok_type);
+makeTokenHeader(size_t body_size,
+ unsigned char **buf);
OM_uint32
verifyTokenHeader(OM_uint32 *minor,
}
#endif
+ #include "util_json.h"
#include "util_attr.h"
+ #include "util_base64.h"
#ifdef GSSEAP_ENABLE_REAUTH
#include "util_reauth.h"
#endif
#include <typeinfo>
#include <string>
+ #include <sstream>
#include <exception>
+ #include <stdexcept>
#include <new>
/* lazy initialisation */
return ret;
}
- #define UPDATE_REMAIN(n) do { \
- p += (n); \
- remain -= (n); \
- } while (0)
-
- #define CHECK_REMAIN(n) do { \
- if (remain < (n)) { \
- return false; \
- } \
- } while (0)
-
- /*
- * Initialize a context from an exported context or name token
- */
bool
- gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
+ gss_eap_attr_ctx::initWithJsonObject(JSONObject &obj)
{
bool ret = false;
- size_t remain = buffer->length;
- unsigned char *p = (unsigned char *)buffer->value;
- bool didInit[ATTR_TYPE_MAX + 1];
+ bool foundSource[ATTR_TYPE_MAX + 1];
unsigned int type;
for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++)
- didInit[type] = false;
-
- /* flags */
- CHECK_REMAIN(4);
- m_flags = load_uint32_be(p);
- UPDATE_REMAIN(4);
+ foundSource[type] = false;
- while (remain) {
- OM_uint32 type;
- gss_buffer_desc providerToken;
- gss_eap_attr_provider *provider;
-
- /* TLV encoding of provider type, length, value */
- CHECK_REMAIN(4);
- type = load_uint32_be(p);
- UPDATE_REMAIN(4);
+ if (obj["version"].integer() != 1)
+ return false;
- CHECK_REMAIN(4);
- providerToken.length = load_uint32_be(p);
- UPDATE_REMAIN(4);
+ m_flags = obj["flags"].integer();
- CHECK_REMAIN(providerToken.length);
- providerToken.value = p;
- UPDATE_REMAIN(providerToken.length);
+ JSONObject sources = obj["sources"];
- if (type < ATTR_TYPE_MIN || type > ATTR_TYPE_MAX ||
- didInit[type])
- return false;
+ /* Initialize providers from serialized state */
+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
+ gss_eap_attr_provider *provider;
+ const char *key;
if (!providerEnabled(type)) {
releaseProvider(type);
}
provider = m_providers[type];
+ key = provider->name();
+ if (key == NULL)
+ continue;
- ret = provider->initFromBuffer(this, &providerToken);
- if (ret == false) {
+ JSONObject source = sources.get(key);
+ if (!source.isnull() &&
+ !provider->initWithJsonObject(this, source)) {
releaseProvider(type);
- break;
+ return false;
}
- didInit[type] = true;
- }
- if (ret == false)
- return ret;
+ foundSource[type] = true;
+ }
- /*
- * The call the initFromGssContext methods for attribute
- * providers that can initialize themselves from other
- * providers.
- */
+ /* Initialize remaining providers from initialized providers */
for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
gss_eap_attr_provider *provider;
- if (didInit[type] || !providerEnabled(type))
+ if (foundSource[type] || !providerEnabled(type))
continue;
provider = m_providers[type];
return true;
}
+ JSONObject
+ gss_eap_attr_ctx::jsonRepresentation(void) const
+ {
+ JSONObject obj, sources;
+ unsigned int i;
+
+ obj.set("version", 1);
+ obj.set("flags", m_flags);
+
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider;
+ const char *key;
+
+ provider = m_providers[i];
+ if (provider == NULL)
+ continue; /* provider not initialised */
+
+ key = provider->name();
+ if (key == NULL)
+ continue; /* provider does not have state */
+
+ JSONObject source = provider->jsonRepresentation();
+ sources.set(key, source);
+ }
+
+ obj.set("sources", sources);
+
+ return obj;
+ }
+
+ /*
+ * Initialize a context from an exported context or name token
+ */
+ bool
+ gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
+ {
+ OM_uint32 major, minor;
+ bool ret;
+ char *s;
+ json_error_t error;
+
+ major = bufferToString(&minor, buffer, &s);
+ if (GSS_ERROR(major))
+ return false;
+
+ JSONObject obj = JSONObject::load(s, 0, &error);
+ if (!obj.isnull()) {
+ ret = initWithJsonObject(obj);
+ } else
+ ret = false;
+
+ GSSEAP_FREE(s);
+
+ return ret;
+ }
+
gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
{
for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
unsigned int i;
major = gss_create_empty_buffer_set(&minor, attrs);
- if (GSS_ERROR(major)) {
+ if (GSS_ERROR(major))
throw new std::bad_alloc;
- return false;
- }
args.attrs = *attrs;
void
gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
{
- OM_uint32 tmpMinor;
- gss_buffer_desc providerTokens[ATTR_TYPE_MAX + 1];
- size_t length = 4; /* m_flags */
- unsigned char *p;
- unsigned int i;
+ OM_uint32 minor;
+ char *s;
- for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
- providerTokens[i].length = 0;
- providerTokens[i].value = NULL;
- }
+ JSONObject obj = jsonRepresentation();
- for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
- gss_eap_attr_provider *provider = m_providers[i];
-
- if (provider == NULL)
- continue;
-
- provider->exportToBuffer(&providerTokens[i]);
+ #if 0
+ obj.dump(stdout, JSON_INDENT(3));
+ #endif
- if (providerTokens[i].value != NULL)
- length += 8 + providerTokens[i].length;
- }
+ s = obj.dump(JSON_COMPACT);
- buffer->length = length;
- buffer->value = GSSEAP_MALLOC(length);
- if (buffer->value == NULL)
+ if (GSS_ERROR(makeStringBuffer(&minor, s, buffer)))
throw new std::bad_alloc;
-
- p = (unsigned char *)buffer->value;
- store_uint32_be(m_flags, p);
- p += 4;
-
- for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
- if (providerTokens[i].value == NULL)
- continue;
-
- store_uint32_be(i, p);
- p += 4;
- store_uint32_be(providerTokens[i].length, p);
- p += 4;
- memcpy(p, providerTokens[i].value, providerTokens[i].length);
- p += providerTokens[i].length;
-
- gss_release_buffer(&tmpMinor, &providerTokens[i]);
- }
}
/*
return GSS_S_UNAVAILABLE;
}
- try {
- if (!name->attrCtx->getAttributeTypes(attrs)) {
- *minor = GSSEAP_NO_ATTR_CONTEXT;
- return GSS_S_UNAVAILABLE;
+ if (attrs != NULL) {
+ try {
+ if (!name->attrCtx->getAttributeTypes(attrs)) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+ } catch (std::exception &e) {
+ return name->attrCtx->mapException(minor, e);
}
- } catch (std::exception &e) {
- return name->attrCtx->mapException(minor, e);
}
return GSS_S_COMPLETE;
major = GSS_S_FAILURE;
try {
- ctx = new gss_eap_attr_ctx();
+ *pAttrContext = ctx = new gss_eap_attr_ctx();
if (ctx->initFromGssContext(gssCred, gssCtx)) {
*minor = 0;
major = GSS_S_COMPLETE;
- } else {
- delete ctx;
}
} catch (std::exception &e) {
if (ctx != NULL)
}
if (major == GSS_S_COMPLETE) {
- *pAttrContext = ctx;
*pExpiryTime = ctx->getExpiryTime();
+ } else {
+ delete ctx;
+ *pAttrContext = NULL;
}
return major;