From e892880f0248996135770c9f31a1f83fece3ae1d Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Tue, 4 Oct 2011 10:22:14 +1100 Subject: [PATCH] NegoEx SPIs --- mech_eap/Makefile.am | 3 + mech_eap/exchange_meta_data.c | 82 +++++++++++++++++++ mech_eap/gssapiP_eap.h | 27 +++++++ mech_eap/init_sec_context.c | 2 - mech_eap/inquire_sec_context_by_oid.c | 147 +++++++++++++++++++++++++++++----- mech_eap/mech_eap-noacceptor.exports | 3 + mech_eap/mech_eap.exports | 3 + mech_eap/query_mechanism_info.c | 59 ++++++++++++++ mech_eap/query_meta_data.c | 116 +++++++++++++++++++++++++++ 9 files changed, 420 insertions(+), 22 deletions(-) create mode 100644 mech_eap/exchange_meta_data.c create mode 100644 mech_eap/query_mechanism_info.c create mode 100644 mech_eap/query_meta_data.c diff --git a/mech_eap/Makefile.am b/mech_eap/Makefile.am index 5f78a77..cb66fe8 100644 --- a/mech_eap/Makefile.am +++ b/mech_eap/Makefile.am @@ -62,6 +62,7 @@ mech_eap_la_SOURCES = \ display_status.c \ duplicate_name.c \ eap_mech.c \ + exchange_meta_data.c \ export_name.c \ export_sec_context.c \ get_mic.c \ @@ -82,6 +83,8 @@ mech_eap_la_SOURCES = \ inquire_sec_context_by_oid.c \ process_context_token.c \ pseudo_random.c \ + query_mechanism_info.c \ + query_meta_data.c \ radsec_err.c \ release_cred.c \ release_name.c \ diff --git a/mech_eap/exchange_meta_data.c b/mech_eap/exchange_meta_data.c new file mode 100644 index 0000000..5d56795 --- /dev/null +++ b/mech_eap/exchange_meta_data.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gssEapExchangeMetaData(OM_uint32 *minor, + gss_const_OID mech GSSEAP_UNUSED, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t *ctx GSSEAP_UNUSED, + const gss_name_t name GSSEAP_UNUSED, + OM_uint32 req_flags GSSEAP_UNUSED, + gss_const_buffer_t meta_data GSSEAP_UNUSED) +{ + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_exchange_meta_data(OM_uint32 *minor, + gss_const_OID mech, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + const gss_name_t name, + OM_uint32 req_flags, + gss_const_buffer_t meta_data) +{ + gss_ctx_id_t ctx = *context_handle; + OM_uint32 major; + + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_LOCK(&cred->mutex); + + if (*context_handle != GSS_C_NO_CONTEXT) + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + major = gssEapExchangeMetaData(minor, mech, cred, &ctx, + name, req_flags, meta_data); + + if (*context_handle != GSS_C_NO_CONTEXT) + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + else + *context_handle = ctx; + + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + + return major; +} diff --git a/mech_eap/gssapiP_eap.h b/mech_eap/gssapiP_eap.h index 8b498e9..f42f7be 100644 --- a/mech_eap/gssapiP_eap.h +++ b/mech_eap/gssapiP_eap.h @@ -342,6 +342,16 @@ gssEapDisplayStatus(OM_uint32 *minor, #define IS_RADIUS_ERROR(err) ((err) >= ERROR_TABLE_BASE_rse && \ (err) <= ERROR_TABLE_BASE_rse + 20) +/* exchange_meta_data.c */ +OM_uint32 GSSAPI_CALLCONV +gssEapExchangeMetaData(OM_uint32 *minor, + gss_const_OID mech, + gss_cred_id_t cred, + gss_ctx_id_t *ctx, + const gss_name_t name, + OM_uint32 req_flags, + gss_const_buffer_t meta_data); + /* export_sec_context.c */ OM_uint32 gssEapExportSecContext(OM_uint32 *minor, @@ -354,6 +364,13 @@ gssEapImportContext(OM_uint32 *minor, gss_buffer_t token, gss_ctx_id_t ctx); +/* inquire_sec_context_by_oid.c */ +#define NEGOEX_INITIATOR_SALT "gss-eap-negoex-initiator" +#define NEGOEX_INITIATOR_SALT_LEN (sizeof(NEGOEX_INITIATOR_SALT) - 1) + +#define NEGOEX_ACCEPTOR_SALT "gss-eap-negoex-acceptor" +#define NEGOEX_ACCEPTOR_SALT_LEN (sizeof(NEGOEX_ACCEPTOR_SALT) - 1) + /* pseudo_random.c */ OM_uint32 gssEapPseudoRandom(OM_uint32 *minor, @@ -363,6 +380,16 @@ gssEapPseudoRandom(OM_uint32 *minor, ssize_t desired_output_len, gss_buffer_t prf_out); +/* query_meta_data.c */ +OM_uint32 +gssEapQueryMetaData(OM_uint32 *minor, + gss_const_OID mech GSSEAP_UNUSED, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + const gss_name_t name, + OM_uint32 req_flags GSSEAP_UNUSED, + gss_buffer_t meta_data); + /* eap_mech.c */ OM_uint32 gssEapInitiatorInit(OM_uint32 *minor); diff --git a/mech_eap/init_sec_context.c b/mech_eap/init_sec_context.c index dc5c70f..46e925e 100644 --- a/mech_eap/init_sec_context.c +++ b/mech_eap/init_sec_context.c @@ -1048,8 +1048,6 @@ gss_init_sec_context(OM_uint32 *minor, output_token->length = 0; output_token->value = NULL; - GSSEAP_ASSERT(ctx == GSS_C_NO_CONTEXT || ctx->mechanismUsed != GSS_C_NO_OID); - if (ctx == GSS_C_NO_CONTEXT) { if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) { *minor = GSSEAP_WRONG_SIZE; diff --git a/mech_eap/inquire_sec_context_by_oid.c b/mech_eap/inquire_sec_context_by_oid.c index 67b2ec8..7435f2e 100644 --- a/mech_eap/inquire_sec_context_by_oid.c +++ b/mech_eap/inquire_sec_context_by_oid.c @@ -37,15 +37,64 @@ #include "gssapiP_eap.h" static OM_uint32 +addEnctypeOidToBufferSet(OM_uint32 *minor, + krb5_enctype encryptionType, + gss_buffer_set_t *dataSet) +{ + OM_uint32 major; + unsigned char oidBuf[16]; + gss_OID_desc oid; + gss_buffer_desc buf; + + oid.length = sizeof(oidBuf); + oid.elements = oidBuf; + + major = composeOid(minor, + "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04", + 10, + encryptionType, + &oid); + if (GSS_ERROR(major)) + return major; + + buf.length = oid.length; + buf.value = oid.elements; + + major = gss_add_buffer_set_member(minor, &buf, dataSet); + + return major; +} + +static void +zeroAndReleaseBufferSet(gss_buffer_set_t *dataSet) +{ + OM_uint32 tmpMinor; + gss_buffer_set_t set = *dataSet; + size_t i; + + if (set == GSS_C_NO_BUFFER_SET) + return; + + for (i = 0; i count; i++) + memset(set->elements[i].value, 0, set->elements[i].length); + + gss_release_buffer_set(&tmpMinor, dataSet); +} + +static OM_uint32 inquireSessionKey(OM_uint32 *minor, const gss_ctx_id_t ctx, const gss_OID desired_object GSSEAP_UNUSED, gss_buffer_set_t *dataSet) { - OM_uint32 major, tmpMinor; - unsigned char oidBuf[16]; + OM_uint32 major; gss_buffer_desc buf; - gss_OID_desc oid; + + if (ctx->encryptionType == ENCTYPE_NULL) { + major = GSS_S_UNAVAILABLE; + *minor = GSSEAP_KEY_UNAVAILABLE; + goto cleanup; + } buf.length = KRB_KEY_LENGTH(&ctx->rfc3961Key); buf.value = KRB_KEY_DATA(&ctx->rfc3961Key); @@ -54,21 +103,69 @@ inquireSessionKey(OM_uint32 *minor, if (GSS_ERROR(major)) goto cleanup; - oid.length = sizeof(oidBuf); - oid.elements = oidBuf; + major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet); + if (GSS_ERROR(major)) + goto cleanup; - major = composeOid(minor, - "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04", - 10, - ctx->encryptionType, - &oid); + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: if (GSS_ERROR(major)) + zeroAndReleaseBufferSet(dataSet); + + return major; +} + +static OM_uint32 +inquireNegoExKey(OM_uint32 *minor, + const gss_ctx_id_t ctx, + const gss_OID desired_object, + gss_buffer_set_t *dataSet) +{ + OM_uint32 major, tmpMinor; + int bInitiatorKey; + gss_buffer_desc salt; + gss_buffer_desc key = GSS_C_EMPTY_BUFFER; + size_t keySize; + + bInitiatorKey = CTX_IS_INITIATOR(ctx); + + if (ctx->encryptionType == ENCTYPE_NULL) { + major = GSS_S_UNAVAILABLE; + *minor = GSSEAP_KEY_UNAVAILABLE; goto cleanup; + } - buf.length = oid.length; - buf.value = oid.elements; + /* + * If the caller supplied the verify key OID, then we need the acceptor + * key if we are the initiator, and vice versa. + */ + if (desired_object->length == 11 && + memcmp(desired_object->elements, + "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07", 11) == 0) + bInitiatorKey ^= 1; + + if (bInitiatorKey) { + salt.length = NEGOEX_INITIATOR_SALT_LEN; + salt.value = NEGOEX_INITIATOR_SALT; + } else { + salt.length = NEGOEX_ACCEPTOR_SALT_LEN; + salt.value = NEGOEX_ACCEPTOR_SALT; + } - major = gss_add_buffer_set_member(minor, &buf, dataSet); + keySize = KRB_KEY_LENGTH(&ctx->rfc3961Key); + + major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt, + keySize, &key); + if (GSS_ERROR(major)) + goto cleanup; + + major = gss_add_buffer_set_member(minor, &key, dataSet); + if (GSS_ERROR(major)) + goto cleanup; + + major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet); if (GSS_ERROR(major)) goto cleanup; @@ -76,13 +173,12 @@ inquireSessionKey(OM_uint32 *minor, *minor = 0; cleanup: - if (GSS_ERROR(major) && *dataSet != GSS_C_NO_BUFFER_SET) { - gss_buffer_set_t set = *dataSet; - - if (set->count != 0) - memset(set->elements[0].value, 0, set->elements[0].length); - gss_release_buffer_set(&tmpMinor, dataSet); + if (key.value != NULL) { + memset(key.value, 0, key.length); + gss_release_buffer(&tmpMinor, &key); } + if (GSS_ERROR(major)) + zeroAndReleaseBufferSet(dataSet); return major; } @@ -102,6 +198,16 @@ static struct { { 12, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06\x01" }, gssEapExportLucidSecContext }, + { + /* GSS_C_INQ_NEGOEX_KEY */ + { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06" }, + inquireNegoExKey + }, + { + /* GSS_C_INQ_NEGOEX_VERIFY_KEY */ + { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07" }, + inquireNegoExKey + }, }; OM_uint32 GSSAPI_CALLCONV @@ -117,11 +223,13 @@ gss_inquire_sec_context_by_oid(OM_uint32 *minor, GSSEAP_MUTEX_LOCK(&ctx->mutex); +#if 0 if (!CTX_IS_ESTABLISHED(ctx)) { *minor = GSSEAP_CONTEXT_INCOMPLETE; major = GSS_S_NO_CONTEXT; goto cleanup; } +#endif major = GSS_S_UNAVAILABLE; *minor = GSSEAP_BAD_CONTEXT_OPTION; @@ -134,7 +242,6 @@ gss_inquire_sec_context_by_oid(OM_uint32 *minor, } } -cleanup: GSSEAP_MUTEX_UNLOCK(&ctx->mutex); return major; diff --git a/mech_eap/mech_eap-noacceptor.exports b/mech_eap/mech_eap-noacceptor.exports index 4ecbc52..f00df8a 100644 --- a/mech_eap/mech_eap-noacceptor.exports +++ b/mech_eap/mech_eap-noacceptor.exports @@ -9,6 +9,7 @@ gss_display_name gss_display_name_ext gss_display_status gss_duplicate_name +gss_exchange_meta_data gss_export_name gss_export_sec_context gss_get_mic @@ -28,6 +29,8 @@ gss_inquire_saslname_for_mech gss_inquire_sec_context_by_oid gss_process_context_token gss_pseudo_random +gss_query_mechanism_info +gss_query_meta_data gss_release_cred gss_release_name gss_internal_release_oid diff --git a/mech_eap/mech_eap.exports b/mech_eap/mech_eap.exports index 10c7f81..6a17a17 100644 --- a/mech_eap/mech_eap.exports +++ b/mech_eap/mech_eap.exports @@ -11,6 +11,7 @@ gss_display_name gss_display_name_ext gss_display_status gss_duplicate_name +gss_exchange_meta_data gss_export_name gss_export_name_composite gss_export_sec_context @@ -34,6 +35,8 @@ gss_inquire_sec_context_by_oid gss_map_name_to_any gss_process_context_token gss_pseudo_random +gss_query_mechanism_info +gss_query_meta_data gss_release_any_name_mapping gss_release_cred gss_release_name diff --git a/mech_eap/query_mechanism_info.c b/mech_eap/query_mechanism_info.c new file mode 100644 index 0000000..3971ed4 --- /dev/null +++ b/mech_eap/query_mechanism_info.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_query_mechanism_info(OM_uint32 *minor, + gss_const_OID mech_oid, + unsigned char auth_scheme[16]) +{ + OM_uint32 major; + krb5_enctype enctype; + + major = gssEapOidToEnctype(minor, (const gss_OID)mech_oid, &enctype); + if (GSS_ERROR(major)) + return major; + + /* the enctype is encoded in the increasing part of the GUID */ + memcpy(auth_scheme, + "\x39\xd7\x7d\x00\xe5\x00\x11\xe0\xac\x64\xcd\x53\x46\x50\xac\xb9", 16); + + auth_scheme[3] = (unsigned char)enctype; + + *minor = 0; + return GSS_S_COMPLETE; +} diff --git a/mech_eap/query_meta_data.c b/mech_eap/query_meta_data.c new file mode 100644 index 0000000..ad3a6ca --- /dev/null +++ b/mech_eap/query_meta_data.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * + */ + +#include "gssapiP_eap.h" + +OM_uint32 +gssEapQueryMetaData(OM_uint32 *minor, + gss_const_OID mech GSSEAP_UNUSED, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + const gss_name_t name, + OM_uint32 req_flags GSSEAP_UNUSED, + gss_buffer_t meta_data) +{ + OM_uint32 major; + int isInitiator = (name != GSS_C_NO_NAME); + gss_ctx_id_t ctx = *context_handle; + + meta_data->length = 0; + meta_data->value = NULL; + + if (ctx == GSS_C_NO_CONTEXT) { + major = gssEapAllocContext(minor, &ctx); + if (GSS_ERROR(major)) + return major; + + if (isInitiator) + ctx->flags |= CTX_FLAG_INITIATOR; + } + + if (ctx->cred == GSS_C_NO_CREDENTIAL) { + if (isInitiator) { + major = gssEapResolveInitiatorCred(minor, cred, + name, &ctx->cred); + } else { + major = gssEapAcquireCred(minor, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_ACCEPT, + &ctx->cred, + NULL, + NULL); + } + } + + if (*context_handle == GSS_C_NO_CONTEXT) + *context_handle = ctx; + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +gss_query_meta_data(OM_uint32 *minor, + gss_const_OID mech, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + const gss_name_t name, + OM_uint32 req_flags, + gss_buffer_t meta_data) +{ + gss_ctx_id_t ctx = *context_handle; + OM_uint32 major; + + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_LOCK(&cred->mutex); + + if (*context_handle != GSS_C_NO_CONTEXT) + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + major = gssEapQueryMetaData(minor, mech, cred, &ctx, + name, req_flags, meta_data); + + if (*context_handle != GSS_C_NO_CONTEXT) + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + else + *context_handle = ctx; + + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + + return major; +} -- 2.1.4