|
Packit Service |
99d1c0 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* Copyright (C) 2011-2018 PADL Software Pty Ltd.
|
|
Packit Service |
99d1c0 |
* All rights reserved.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit Service |
99d1c0 |
* modification, are permitted provided that the following conditions
|
|
Packit Service |
99d1c0 |
* are met:
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* * Redistributions of source code must retain the above copyright
|
|
Packit Service |
99d1c0 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* * Redistributions in binary form must reproduce the above copyright
|
|
Packit Service |
99d1c0 |
* notice, this list of conditions and the following disclaimer in
|
|
Packit Service |
99d1c0 |
* the documentation and/or other materials provided with the
|
|
Packit Service |
99d1c0 |
* distribution.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit Service |
99d1c0 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit Service |
99d1c0 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
Packit Service |
99d1c0 |
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
Packit Service |
99d1c0 |
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
Packit Service |
99d1c0 |
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
Packit Service |
99d1c0 |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
Packit Service |
99d1c0 |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
Packit Service |
99d1c0 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
Packit Service |
99d1c0 |
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit Service |
99d1c0 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
Packit Service |
99d1c0 |
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#include "gssapiP_spnego.h"
|
|
Packit Service |
99d1c0 |
#include <generic/gssapiP_generic.h>
|
|
Packit Service |
99d1c0 |
#include "k5-input.h"
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static void
|
|
Packit Service |
99d1c0 |
release_auth_mech(struct negoex_auth_mech *mech);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
OM_uint32
|
|
Packit Service |
99d1c0 |
negoex_random(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
|
|
Packit Service |
99d1c0 |
uint8_t *data, size_t length)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
krb5_data d = make_data(data, length);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
*minor = krb5_c_random_make_octets(ctx->kctx, &d);
|
|
Packit Service |
99d1c0 |
return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* SPNEGO functions expect to find the active mech context in ctx->ctx_handle,
|
|
Packit Service |
99d1c0 |
* but the metadata exchange APIs force us to have one mech context per mech
|
|
Packit Service |
99d1c0 |
* entry. To address this mismatch, move the active mech context (if we have
|
|
Packit Service |
99d1c0 |
* one) to ctx->ctx_handle at the end of NegoEx processing.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
negoex_prep_context_for_spnego(spnego_gss_ctx_id_t ctx)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct negoex_auth_mech *mech;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
mech = K5_TAILQ_FIRST(&ctx->negoex_mechs);
|
|
Packit Service |
99d1c0 |
if (mech == NULL || mech->mech_context == GSS_C_NO_CONTEXT)
|
|
Packit Service |
99d1c0 |
return;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
assert(ctx->ctx_handle == GSS_C_NO_CONTEXT);
|
|
Packit Service |
99d1c0 |
ctx->ctx_handle = mech->mech_context;
|
|
Packit Service |
99d1c0 |
mech->mech_context = GSS_C_NO_CONTEXT;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
OM_uint32
|
|
Packit Service |
99d1c0 |
negoex_prep_context_for_negoex(OM_uint32 *minor, spnego_gss_ctx_id_t ctx)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
krb5_error_code ret;
|
|
Packit Service |
99d1c0 |
struct negoex_auth_mech *mech;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (ctx->kctx != NULL) {
|
|
Packit Service |
99d1c0 |
/* The context is already initialized for NegoEx. Undo what
|
|
Packit Service |
99d1c0 |
* negoex_prep_for_spnego() did, if applicable. */
|
|
Packit Service |
99d1c0 |
if (ctx->ctx_handle != GSS_C_NO_CONTEXT) {
|
|
Packit Service |
99d1c0 |
mech = K5_TAILQ_FIRST(&ctx->negoex_mechs);
|
|
Packit Service |
99d1c0 |
assert(mech != NULL && mech->mech_context == GSS_C_NO_CONTEXT);
|
|
Packit Service |
99d1c0 |
mech->mech_context = ctx->ctx_handle;
|
|
Packit Service |
99d1c0 |
ctx->ctx_handle = GSS_C_NO_CONTEXT;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
return GSS_S_COMPLETE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Initialize the NegoEX context fields. (negoex_mechs is already set up
|
|
Packit Service |
99d1c0 |
* by SPNEGO.) */
|
|
Packit Service |
99d1c0 |
ret = krb5_init_context(&ctx->kctx);
|
|
Packit Service |
99d1c0 |
if (ret) {
|
|
Packit Service |
99d1c0 |
*minor = ret;
|
|
Packit Service |
99d1c0 |
return GSS_S_FAILURE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
k5_buf_init_dynamic(&ctx->negoex_transcript);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return GSS_S_COMPLETE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static void
|
|
Packit Service |
99d1c0 |
release_all_mechs(spnego_gss_ctx_id_t ctx)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct negoex_auth_mech *mech, *next;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
K5_TAILQ_FOREACH_SAFE(mech, &ctx->negoex_mechs, links, next)
|
|
Packit Service |
99d1c0 |
release_auth_mech(mech);
|
|
Packit Service |
99d1c0 |
K5_TAILQ_INIT(&ctx->negoex_mechs);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
negoex_release_context(spnego_gss_ctx_id_t ctx)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
k5_buf_free(&ctx->negoex_transcript);
|
|
Packit Service |
99d1c0 |
release_all_mechs(ctx);
|
|
Packit Service |
99d1c0 |
krb5_free_context(ctx->kctx);
|
|
Packit Service |
99d1c0 |
ctx->kctx = NULL;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static const char *
|
|
Packit Service |
99d1c0 |
typestr(enum message_type type)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
if (type == INITIATOR_NEGO)
|
|
Packit Service |
99d1c0 |
return "INITIATOR_NEGO";
|
|
Packit Service |
99d1c0 |
else if (type == ACCEPTOR_NEGO)
|
|
Packit Service |
99d1c0 |
return "ACCEPTOR_NEGO";
|
|
Packit Service |
99d1c0 |
else if (type == INITIATOR_META_DATA)
|
|
Packit Service |
99d1c0 |
return "INITIATOR_META_DATA";
|
|
Packit Service |
99d1c0 |
else if (type == ACCEPTOR_META_DATA)
|
|
Packit Service |
99d1c0 |
return "ACCEPTOR_META_DATA";
|
|
Packit Service |
99d1c0 |
else if (type == CHALLENGE)
|
|
Packit Service |
99d1c0 |
return "CHALLENGE";
|
|
Packit Service |
99d1c0 |
else if (type == AP_REQUEST)
|
|
Packit Service |
99d1c0 |
return "AP_REQUEST";
|
|
Packit Service |
99d1c0 |
else if (type == VERIFY)
|
|
Packit Service |
99d1c0 |
return "VERIFY";
|
|
Packit Service |
99d1c0 |
else if (type == ALERT)
|
|
Packit Service |
99d1c0 |
return "ALERT";
|
|
Packit Service |
99d1c0 |
else
|
|
Packit Service |
99d1c0 |
return "UNKNOWN";
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static void
|
|
Packit Service |
99d1c0 |
add_guid(struct k5buf *buf, const uint8_t guid[GUID_LENGTH])
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
uint32_t data1 = load_32_le(guid);
|
|
Packit Service |
99d1c0 |
uint16_t data2 = load_16_le(guid + 4), data3 = load_16_le(guid + 6);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
k5_buf_add_fmt(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
|
Packit Service |
99d1c0 |
data1, data2, data3, guid[8], guid[9], guid[10], guid[11],
|
|
Packit Service |
99d1c0 |
guid[12], guid[13], guid[14], guid[15]);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static char *
|
|
Packit Service |
99d1c0 |
guid_to_string(const uint8_t guid[GUID_LENGTH])
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct k5buf buf;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
k5_buf_init_dynamic(&buf;;
|
|
Packit Service |
99d1c0 |
add_guid(&buf, guid);
|
|
Packit Service |
99d1c0 |
return buf.data;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Check that the described vector lies within the message, and return a
|
|
Packit Service |
99d1c0 |
* pointer to its first element. */
|
|
Packit Service |
99d1c0 |
static inline const uint8_t *
|
|
Packit Service |
99d1c0 |
vector_base(size_t offset, size_t count, size_t width,
|
|
Packit Service |
99d1c0 |
const uint8_t *msg_base, size_t msg_len)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
if (offset > msg_len || count > (msg_len - offset) / width)
|
|
Packit Service |
99d1c0 |
return NULL;
|
|
Packit Service |
99d1c0 |
return msg_base + offset;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Trace a received message. Call after the context sequence number is
|
|
Packit Service |
99d1c0 |
* incremented. */
|
|
Packit Service |
99d1c0 |
static void
|
|
Packit Service |
99d1c0 |
trace_received_message(spnego_gss_ctx_id_t ctx,
|
|
Packit Service |
99d1c0 |
const struct negoex_message *msg)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct k5buf buf;
|
|
Packit Service |
99d1c0 |
uint16_t i;
|
|
Packit Service |
99d1c0 |
char *info = NULL;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (msg->type == INITIATOR_NEGO || msg->type == ACCEPTOR_NEGO) {
|
|
Packit Service |
99d1c0 |
k5_buf_init_dynamic(&buf;;
|
|
Packit Service |
99d1c0 |
for (i = 0; i < msg->u.n.nschemes; i++) {
|
|
Packit Service |
99d1c0 |
add_guid(&buf, msg->u.n.schemes + i * GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
if (i + 1 < msg->u.n.nschemes)
|
|
Packit Service |
99d1c0 |
k5_buf_add(&buf, " ");
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
info = buf.data;
|
|
Packit Service |
99d1c0 |
} else if (msg->type == INITIATOR_META_DATA ||
|
|
Packit Service |
99d1c0 |
msg->type == ACCEPTOR_META_DATA ||
|
|
Packit Service |
99d1c0 |
msg->type == CHALLENGE || msg->type == AP_REQUEST) {
|
|
Packit Service |
99d1c0 |
info = guid_to_string(msg->u.e.scheme);
|
|
Packit Service |
99d1c0 |
} else if (msg->type == VERIFY) {
|
|
Packit Service |
99d1c0 |
info = guid_to_string(msg->u.v.scheme);
|
|
Packit Service |
99d1c0 |
} else if (msg->type == ALERT) {
|
|
Packit Service |
99d1c0 |
info = guid_to_string(msg->u.a.scheme);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (info == NULL)
|
|
Packit Service |
99d1c0 |
return;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
TRACE_NEGOEX_INCOMING(ctx->kctx, ctx->negoex_seqnum - 1,
|
|
Packit Service |
99d1c0 |
typestr(msg->type), info);
|
|
Packit Service |
99d1c0 |
free(info);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Trace an outgoing message with a GUID info string. Call after the context
|
|
Packit Service |
99d1c0 |
* sequence number is incremented. */
|
|
Packit Service |
99d1c0 |
static void
|
|
Packit Service |
99d1c0 |
trace_outgoing_message(spnego_gss_ctx_id_t ctx, enum message_type type,
|
|
Packit Service |
99d1c0 |
const uint8_t guid[GUID_LENGTH])
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
char *info = guid_to_string(guid);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (info == NULL)
|
|
Packit Service |
99d1c0 |
return;
|
|
Packit Service |
99d1c0 |
TRACE_NEGOEX_OUTGOING(ctx->kctx, ctx->negoex_seqnum - 1, typestr(type),
|
|
Packit Service |
99d1c0 |
info);
|
|
Packit Service |
99d1c0 |
free(info);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static OM_uint32
|
|
Packit Service |
99d1c0 |
parse_nego_message(OM_uint32 *minor, struct k5input *in,
|
|
Packit Service |
99d1c0 |
const uint8_t *msg_base, size_t msg_len,
|
|
Packit Service |
99d1c0 |
struct nego_message *msg)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
const uint8_t *p;
|
|
Packit Service |
99d1c0 |
uint64_t protocol_version;
|
|
Packit Service |
99d1c0 |
uint32_t extension_type;
|
|
Packit Service |
99d1c0 |
size_t offset, count, i;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
p = k5_input_get_bytes(in, sizeof(msg->random));
|
|
Packit Service |
99d1c0 |
if (p != NULL)
|
|
Packit Service |
99d1c0 |
memcpy(msg->random, p, sizeof(msg->random));
|
|
Packit Service |
99d1c0 |
protocol_version = k5_input_get_uint64_le(in);
|
|
Packit Service |
99d1c0 |
if (protocol_version != 0) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_UNSUPPORTED_VERSION;
|
|
Packit Service |
99d1c0 |
return GSS_S_UNAVAILABLE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
offset = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
count = k5_input_get_uint16_le(in);
|
|
Packit Service |
99d1c0 |
msg->schemes = vector_base(offset, count, GUID_LENGTH, msg_base, msg_len);
|
|
Packit Service |
99d1c0 |
msg->nschemes = count;
|
|
Packit Service |
99d1c0 |
if (msg->schemes == NULL) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_INVALID_MESSAGE_SIZE;
|
|
Packit Service |
99d1c0 |
return GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
offset = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
count = k5_input_get_uint16_le(in);
|
|
Packit Service |
99d1c0 |
p = vector_base(offset, count, EXTENSION_LENGTH, msg_base, msg_len);
|
|
Packit Service |
99d1c0 |
for (i = 0; i < count; i++) {
|
|
Packit Service |
99d1c0 |
extension_type = load_32_le(p + i * EXTENSION_LENGTH);
|
|
Packit Service |
99d1c0 |
if (extension_type & EXTENSION_FLAG_CRITICAL) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_UNSUPPORTED_CRITICAL_EXTENSION;
|
|
Packit Service |
99d1c0 |
return GSS_S_UNAVAILABLE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return GSS_S_COMPLETE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static OM_uint32
|
|
Packit Service |
99d1c0 |
parse_exchange_message(OM_uint32 *minor, struct k5input *in,
|
|
Packit Service |
99d1c0 |
const uint8_t *msg_base, size_t msg_len,
|
|
Packit Service |
99d1c0 |
struct exchange_message *msg)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
const uint8_t *p;
|
|
Packit Service |
99d1c0 |
size_t offset, len;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
p = k5_input_get_bytes(in, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
if (p != NULL)
|
|
Packit Service |
99d1c0 |
memcpy(msg->scheme, p, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
offset = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
len = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
p = vector_base(offset, len, 1, msg_base, msg_len);
|
|
Packit Service |
99d1c0 |
if (p == NULL) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_INVALID_MESSAGE_SIZE;
|
|
Packit Service |
99d1c0 |
return GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
msg->token.value = (void *)p;
|
|
Packit Service |
99d1c0 |
msg->token.length = len;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return GSS_S_COMPLETE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static OM_uint32
|
|
Packit Service |
99d1c0 |
parse_verify_message(OM_uint32 *minor, struct k5input *in,
|
|
Packit Service |
99d1c0 |
const uint8_t *msg_base, size_t msg_len,
|
|
Packit Service |
99d1c0 |
size_t token_offset, struct verify_message *msg)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
const uint8_t *p;
|
|
Packit Service |
99d1c0 |
size_t offset, len;
|
|
Packit Service |
99d1c0 |
uint32_t hdrlen, cksum_scheme;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
p = k5_input_get_bytes(in, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
if (p != NULL)
|
|
Packit Service |
99d1c0 |
memcpy(msg->scheme, p, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
hdrlen = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
if (hdrlen != CHECKSUM_HEADER_LENGTH) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_INVALID_MESSAGE_SIZE;
|
|
Packit Service |
99d1c0 |
return GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
cksum_scheme = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
if (cksum_scheme != CHECKSUM_SCHEME_RFC3961) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_UNKNOWN_CHECKSUM_SCHEME;
|
|
Packit Service |
99d1c0 |
return GSS_S_UNAVAILABLE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
msg->cksum_type = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
offset = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
len = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
msg->cksum = vector_base(offset, len, 1, msg_base, msg_len);
|
|
Packit Service |
99d1c0 |
msg->cksum_len = len;
|
|
Packit Service |
99d1c0 |
if (msg->cksum == NULL) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_INVALID_MESSAGE_SIZE;
|
|
Packit Service |
99d1c0 |
return GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
msg->offset_in_token = token_offset;
|
|
Packit Service |
99d1c0 |
return GSS_S_COMPLETE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static OM_uint32
|
|
Packit Service |
99d1c0 |
parse_alert_message(OM_uint32 *minor, struct k5input *in,
|
|
Packit Service |
99d1c0 |
const uint8_t *msg_base, size_t msg_len,
|
|
Packit Service |
99d1c0 |
struct alert_message *msg)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
const uint8_t *p;
|
|
Packit Service |
99d1c0 |
uint32_t atype, reason;
|
|
Packit Service |
99d1c0 |
size_t alerts_offset, nalerts, value_offset, value_len, i;
|
|
Packit Service |
99d1c0 |
struct k5input alerts_in, pulse_in;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
p = k5_input_get_bytes(in, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
if (p != NULL)
|
|
Packit Service |
99d1c0 |
memcpy(msg->scheme, p, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
(void)k5_input_get_uint32_le(in); /* skip over ErrorCode */
|
|
Packit Service |
99d1c0 |
alerts_offset = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
nalerts = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
p = vector_base(alerts_offset, nalerts, ALERT_LENGTH, msg_base, msg_len);
|
|
Packit Service |
99d1c0 |
if (p == NULL) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_INVALID_MESSAGE_SIZE;
|
|
Packit Service |
99d1c0 |
return GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Look for a VERIFY_NO_KEY pulse alert in the alerts vector. */
|
|
Packit Service |
99d1c0 |
msg->verify_no_key = FALSE;
|
|
Packit Service |
99d1c0 |
k5_input_init(&alerts_in, p, nalerts * ALERT_LENGTH);
|
|
Packit Service |
99d1c0 |
for (i = 0; i < nalerts; i++) {
|
|
Packit Service |
99d1c0 |
atype = k5_input_get_uint32_le(&alerts_in);
|
|
Packit Service |
99d1c0 |
value_offset = k5_input_get_uint32_le(&alerts_in);
|
|
Packit Service |
99d1c0 |
value_len = k5_input_get_uint32_le(&alerts_in);
|
|
Packit Service |
99d1c0 |
p = vector_base(value_offset, value_len, 1, msg_base, msg_len);
|
|
Packit Service |
99d1c0 |
if (p == NULL) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_INVALID_MESSAGE_SIZE;
|
|
Packit Service |
99d1c0 |
return GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (atype == ALERT_TYPE_PULSE && value_len >= ALERT_PULSE_LENGTH) {
|
|
Packit Service |
99d1c0 |
k5_input_init(&pulse_in, p, value_len);
|
|
Packit Service |
99d1c0 |
(void)k5_input_get_uint32_le(&pulse_in); /* skip header length */
|
|
Packit Service |
99d1c0 |
reason = k5_input_get_uint32_le(&pulse_in);
|
|
Packit Service |
99d1c0 |
if (reason == ALERT_VERIFY_NO_KEY)
|
|
Packit Service |
99d1c0 |
msg->verify_no_key = TRUE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return GSS_S_COMPLETE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static OM_uint32
|
|
Packit Service |
99d1c0 |
parse_message(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, struct k5input *in,
|
|
Packit Service |
99d1c0 |
const uint8_t *token_base, struct negoex_message *msg)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
OM_uint32 major;
|
|
Packit Service |
99d1c0 |
const uint8_t *msg_base = in->ptr, *conv_id;
|
|
Packit Service |
99d1c0 |
size_t token_remaining = in->len, header_len, msg_len;
|
|
Packit Service |
99d1c0 |
uint64_t signature;
|
|
Packit Service |
99d1c0 |
uint32_t type, seqnum;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
signature = k5_input_get_uint64_le(in);
|
|
Packit Service |
99d1c0 |
type = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
seqnum = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
header_len = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
msg_len = k5_input_get_uint32_le(in);
|
|
Packit Service |
99d1c0 |
conv_id = k5_input_get_bytes(in, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (in->status || msg_len > token_remaining || header_len > msg_len) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_INVALID_MESSAGE_SIZE;
|
|
Packit Service |
99d1c0 |
return GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
if (signature != MESSAGE_SIGNATURE) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_INVALID_MESSAGE_SIGNATURE;
|
|
Packit Service |
99d1c0 |
return GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
if (seqnum != ctx->negoex_seqnum) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_MESSAGE_OUT_OF_SEQUENCE;
|
|
Packit Service |
99d1c0 |
return GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
if (seqnum == 0) {
|
|
Packit Service |
99d1c0 |
memcpy(ctx->negoex_conv_id, conv_id, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
} else if (!GUID_EQ(conv_id, ctx->negoex_conv_id)) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_INVALID_CONVERSATION_ID;
|
|
Packit Service |
99d1c0 |
return GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Restrict the input region to the header. */
|
|
Packit Service |
99d1c0 |
in->len = header_len - (in->ptr - msg_base);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
msg->type = type;
|
|
Packit Service |
99d1c0 |
if (type == INITIATOR_NEGO || type == ACCEPTOR_NEGO) {
|
|
Packit Service |
99d1c0 |
major = parse_nego_message(minor, in, msg_base, msg_len, &msg->u.n);
|
|
Packit Service |
99d1c0 |
} else if (type == INITIATOR_META_DATA || type == ACCEPTOR_META_DATA ||
|
|
Packit Service |
99d1c0 |
type == CHALLENGE || type == AP_REQUEST) {
|
|
Packit Service |
99d1c0 |
major = parse_exchange_message(minor, in, msg_base, msg_len,
|
|
Packit Service |
99d1c0 |
&msg->u.e);
|
|
Packit Service |
99d1c0 |
} else if (type == VERIFY) {
|
|
Packit Service |
99d1c0 |
major = parse_verify_message(minor, in, msg_base, msg_len,
|
|
Packit Service |
99d1c0 |
msg_base - token_base, &msg->u.v);
|
|
Packit Service |
99d1c0 |
} else if (type == ALERT) {
|
|
Packit Service |
99d1c0 |
major = parse_alert_message(minor, in, msg_base, msg_len, &msg->u.a);
|
|
Packit Service |
99d1c0 |
} else {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_INVALID_MESSAGE_TYPE;
|
|
Packit Service |
99d1c0 |
return GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
if (major != GSS_S_COMPLETE)
|
|
Packit Service |
99d1c0 |
return major;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Reset the input buffer to the remainder of the token. */
|
|
Packit Service |
99d1c0 |
if (!in->status)
|
|
Packit Service |
99d1c0 |
k5_input_init(in, msg_base + msg_len, token_remaining - msg_len);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
ctx->negoex_seqnum++;
|
|
Packit Service |
99d1c0 |
trace_received_message(ctx, msg);
|
|
Packit Service |
99d1c0 |
return GSS_S_COMPLETE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* Parse token into an array of negoex_message structures. All pointer fields
|
|
Packit Service |
99d1c0 |
* within the parsed messages are aliases into token, so the result can be
|
|
Packit Service |
99d1c0 |
* freed with free(). An unknown protocol version, a critical extension, or an
|
|
Packit Service |
99d1c0 |
* unknown checksum scheme will cause a parsing failure. Increment the
|
|
Packit Service |
99d1c0 |
* sequence number in ctx for each message, and record and check the
|
|
Packit Service |
99d1c0 |
* conversation ID in ctx as appropriate.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
OM_uint32
|
|
Packit Service |
99d1c0 |
negoex_parse_token(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
|
|
Packit Service |
99d1c0 |
gss_const_buffer_t token,
|
|
Packit Service |
99d1c0 |
struct negoex_message **messages_out, size_t *count_out)
|
|
Packit Service |
99d1c0 |
{
|
|
rpm-build |
a15610 |
OM_uint32 major = GSS_S_COMPLETE;
|
|
Packit Service |
99d1c0 |
size_t count = 0;
|
|
Packit Service |
99d1c0 |
struct k5input in;
|
|
Packit Service |
99d1c0 |
struct negoex_message *messages = NULL, *newptr;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
*messages_out = NULL;
|
|
Packit Service |
99d1c0 |
*count_out = 0;
|
|
Packit Service |
99d1c0 |
assert(token != GSS_C_NO_BUFFER);
|
|
Packit Service |
99d1c0 |
k5_input_init(&in, token->value, token->length);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
while (in.status == 0 && in.len > 0) {
|
|
Packit Service |
99d1c0 |
newptr = realloc(messages, (count + 1) * sizeof(*newptr));
|
|
Packit Service |
99d1c0 |
if (newptr == NULL) {
|
|
Packit Service |
99d1c0 |
free(messages);
|
|
Packit Service |
99d1c0 |
*minor = ENOMEM;
|
|
Packit Service |
99d1c0 |
return GSS_S_FAILURE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
messages = newptr;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
major = parse_message(minor, ctx, &in, token->value, &messages[count]);
|
|
Packit Service |
99d1c0 |
if (major != GSS_S_COMPLETE)
|
|
Packit Service |
99d1c0 |
break;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
count++;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (in.status) {
|
|
Packit Service |
99d1c0 |
*minor = ERR_NEGOEX_INVALID_MESSAGE_SIZE;
|
|
Packit Service |
99d1c0 |
major = GSS_S_DEFECTIVE_TOKEN;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
if (major != GSS_S_COMPLETE) {
|
|
Packit Service |
99d1c0 |
free(messages);
|
|
Packit Service |
99d1c0 |
return major;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
*messages_out = messages;
|
|
Packit Service |
99d1c0 |
*count_out = count;
|
|
Packit Service |
99d1c0 |
return GSS_S_COMPLETE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static struct negoex_message *
|
|
Packit Service |
99d1c0 |
locate_message(struct negoex_message *messages, size_t nmessages,
|
|
Packit Service |
99d1c0 |
enum message_type type)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
uint32_t i;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
for (i = 0; i < nmessages; i++) {
|
|
Packit Service |
99d1c0 |
if (messages[i].type == type)
|
|
Packit Service |
99d1c0 |
return &messages[i];
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return NULL;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
struct nego_message *
|
|
Packit Service |
99d1c0 |
negoex_locate_nego_message(struct negoex_message *messages, size_t nmessages,
|
|
Packit Service |
99d1c0 |
enum message_type type)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct negoex_message *msg = locate_message(messages, nmessages, type);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return (msg == NULL) ? NULL : &msg->u.n;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
struct exchange_message *
|
|
Packit Service |
99d1c0 |
negoex_locate_exchange_message(struct negoex_message *messages,
|
|
Packit Service |
99d1c0 |
size_t nmessages, enum message_type type)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct negoex_message *msg = locate_message(messages, nmessages, type);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return (msg == NULL) ? NULL : &msg->u.e;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
struct verify_message *
|
|
Packit Service |
99d1c0 |
negoex_locate_verify_message(struct negoex_message *messages,
|
|
Packit Service |
99d1c0 |
size_t nmessages)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct negoex_message *msg = locate_message(messages, nmessages, VERIFY);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return (msg == NULL) ? NULL : &msg->u.v;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
struct alert_message *
|
|
Packit Service |
99d1c0 |
negoex_locate_alert_message(struct negoex_message *messages, size_t nmessages)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct negoex_message *msg = locate_message(messages, nmessages, ALERT);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return (msg == NULL) ? NULL : &msg->u.a;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* Add the encoding of a MESSAGE_HEADER structure to buf, given the number of
|
|
Packit Service |
99d1c0 |
* bytes of the payload following the full header. Increment the sequence
|
|
Packit Service |
99d1c0 |
* number in ctx. Set *payload_start_out to the position of the payload within
|
|
Packit Service |
99d1c0 |
* the message.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
static void
|
|
Packit Service |
99d1c0 |
put_message_header(spnego_gss_ctx_id_t ctx, enum message_type type,
|
|
Packit Service |
99d1c0 |
uint32_t payload_len, uint32_t *payload_start_out)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
size_t header_len;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (type == INITIATOR_NEGO || type == ACCEPTOR_NEGO)
|
|
Packit Service |
99d1c0 |
header_len = NEGO_MESSAGE_HEADER_LENGTH;
|
|
Packit Service |
99d1c0 |
else if (type == INITIATOR_META_DATA || type == ACCEPTOR_META_DATA ||
|
|
Packit Service |
99d1c0 |
type == CHALLENGE || type == AP_REQUEST)
|
|
Packit Service |
99d1c0 |
header_len = EXCHANGE_MESSAGE_HEADER_LENGTH;
|
|
Packit Service |
99d1c0 |
else if (type == VERIFY)
|
|
Packit Service |
99d1c0 |
header_len = VERIFY_MESSAGE_HEADER_LENGTH;
|
|
Packit Service |
99d1c0 |
else if (type == ALERT)
|
|
Packit Service |
99d1c0 |
header_len = ALERT_MESSAGE_HEADER_LENGTH;
|
|
Packit Service |
99d1c0 |
else
|
|
Packit Service |
99d1c0 |
abort();
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint64_le(&ctx->negoex_transcript, MESSAGE_SIGNATURE);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, type);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, ctx->negoex_seqnum++);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, header_len);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, header_len + payload_len);
|
|
Packit Service |
99d1c0 |
k5_buf_add_len(&ctx->negoex_transcript, ctx->negoex_conv_id, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
*payload_start_out = header_len;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
negoex_add_nego_message(spnego_gss_ctx_id_t ctx, enum message_type type,
|
|
Packit Service |
99d1c0 |
uint8_t random[32])
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct negoex_auth_mech *mech;
|
|
Packit Service |
99d1c0 |
uint32_t payload_start, seqnum = ctx->negoex_seqnum;
|
|
Packit Service |
99d1c0 |
uint16_t nschemes;
|
|
Packit Service |
99d1c0 |
struct k5buf buf;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
nschemes = 0;
|
|
Packit Service |
99d1c0 |
K5_TAILQ_FOREACH(mech, &ctx->negoex_mechs, links)
|
|
Packit Service |
99d1c0 |
nschemes++;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
put_message_header(ctx, type, nschemes * GUID_LENGTH, &payload_start);
|
|
Packit Service |
99d1c0 |
k5_buf_add_len(&ctx->negoex_transcript, random, 32);
|
|
Packit Service |
99d1c0 |
/* ProtocolVersion */
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint64_le(&ctx->negoex_transcript, 0);
|
|
Packit Service |
99d1c0 |
/* AuthSchemes vector */
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, payload_start);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint16_le(&ctx->negoex_transcript, nschemes);
|
|
Packit Service |
99d1c0 |
/* Extensions vector */
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, payload_start);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint16_le(&ctx->negoex_transcript, 0);
|
|
Packit Service |
99d1c0 |
/* Four bytes of padding to reach a multiple of 8 bytes. */
|
|
Packit Service |
99d1c0 |
k5_buf_add_len(&ctx->negoex_transcript, "\0\0\0\0", 4);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Payload (auth schemes); also build guid string for tracing. */
|
|
Packit Service |
99d1c0 |
k5_buf_init_dynamic(&buf;;
|
|
Packit Service |
99d1c0 |
K5_TAILQ_FOREACH(mech, &ctx->negoex_mechs, links) {
|
|
Packit Service |
99d1c0 |
k5_buf_add_len(&ctx->negoex_transcript, mech->scheme, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
add_guid(&buf, mech->scheme);
|
|
Packit Service |
99d1c0 |
k5_buf_add(&buf, " ");
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (buf.len > 0) {
|
|
Packit Service |
99d1c0 |
k5_buf_truncate(&buf, buf.len - 1);
|
|
Packit Service |
99d1c0 |
TRACE_NEGOEX_OUTGOING(ctx->kctx, seqnum, typestr(type), buf.data);
|
|
Packit Service |
99d1c0 |
k5_buf_free(&buf;;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
negoex_add_exchange_message(spnego_gss_ctx_id_t ctx, enum message_type type,
|
|
Packit Service |
99d1c0 |
const auth_scheme scheme, gss_buffer_t token)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
uint32_t payload_start;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
put_message_header(ctx, type, token->length, &payload_start);
|
|
Packit Service |
99d1c0 |
k5_buf_add_len(&ctx->negoex_transcript, scheme, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
/* Exchange byte vector */
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, payload_start);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, token->length);
|
|
Packit Service |
99d1c0 |
/* Payload (token) */
|
|
Packit Service |
99d1c0 |
k5_buf_add_len(&ctx->negoex_transcript, token->value, token->length);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
trace_outgoing_message(ctx, type, scheme);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
negoex_add_verify_message(spnego_gss_ctx_id_t ctx, const auth_scheme scheme,
|
|
Packit Service |
99d1c0 |
uint32_t cksum_type, const uint8_t *cksum,
|
|
Packit Service |
99d1c0 |
uint32_t cksum_len)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
uint32_t payload_start;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
put_message_header(ctx, VERIFY, cksum_len, &payload_start);
|
|
Packit Service |
99d1c0 |
k5_buf_add_len(&ctx->negoex_transcript, scheme, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, CHECKSUM_HEADER_LENGTH);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, CHECKSUM_SCHEME_RFC3961);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, cksum_type);
|
|
Packit Service |
99d1c0 |
/* ChecksumValue vector */
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, payload_start);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, cksum_len);
|
|
Packit Service |
99d1c0 |
/* Four bytes of padding to reach a multiple of 8 bytes. */
|
|
Packit Service |
99d1c0 |
k5_buf_add_len(&ctx->negoex_transcript, "\0\0\0\0", 4);
|
|
Packit Service |
99d1c0 |
/* Payload (checksum contents) */
|
|
Packit Service |
99d1c0 |
k5_buf_add_len(&ctx->negoex_transcript, cksum, cksum_len);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
trace_outgoing_message(ctx, VERIFY, scheme);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Add an ALERT_MESSAGE containing a single ALERT_TYPE_PULSE alert with the
|
|
Packit Service |
99d1c0 |
* reason ALERT_VERIFY_NO_KEY. */
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
negoex_add_verify_no_key_alert(spnego_gss_ctx_id_t ctx,
|
|
Packit Service |
99d1c0 |
const auth_scheme scheme)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
uint32_t payload_start;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
put_message_header(ctx, ALERT, ALERT_LENGTH + ALERT_PULSE_LENGTH,
|
|
Packit Service |
99d1c0 |
&payload_start);
|
|
Packit Service |
99d1c0 |
k5_buf_add_len(&ctx->negoex_transcript, scheme, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
/* ErrorCode */
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, 0);
|
|
Packit Service |
99d1c0 |
/* Alerts vector */
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, payload_start);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint16_le(&ctx->negoex_transcript, 1);
|
|
Packit Service |
99d1c0 |
/* Six bytes of padding to reach a multiple of 8 bytes. */
|
|
Packit Service |
99d1c0 |
k5_buf_add_len(&ctx->negoex_transcript, "\0\0\0\0\0\0", 6);
|
|
Packit Service |
99d1c0 |
/* Payload part 1: a single ALERT element */
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, ALERT_TYPE_PULSE);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript,
|
|
Packit Service |
99d1c0 |
payload_start + ALERT_LENGTH);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, ALERT_PULSE_LENGTH);
|
|
Packit Service |
99d1c0 |
/* Payload part 2: ALERT_PULSE */
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, ALERT_PULSE_LENGTH);
|
|
Packit Service |
99d1c0 |
k5_buf_add_uint32_le(&ctx->negoex_transcript, ALERT_VERIFY_NO_KEY);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
trace_outgoing_message(ctx, ALERT, scheme);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static void
|
|
Packit Service |
99d1c0 |
release_auth_mech(struct negoex_auth_mech *mech)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
OM_uint32 tmpmin;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (mech == NULL)
|
|
Packit Service |
99d1c0 |
return;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
gss_delete_sec_context(&tmpmin, &mech->mech_context, NULL);
|
|
Packit Service |
99d1c0 |
generic_gss_release_oid(&tmpmin, &mech->oid);
|
|
Packit Service |
99d1c0 |
gss_release_buffer(&tmpmin, &mech->metadata);
|
|
Packit Service |
99d1c0 |
krb5_free_keyblock_contents(NULL, &mech->key);
|
|
Packit Service |
99d1c0 |
krb5_free_keyblock_contents(NULL, &mech->verify_key);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
free(mech);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
negoex_delete_auth_mech(spnego_gss_ctx_id_t ctx,
|
|
Packit Service |
99d1c0 |
struct negoex_auth_mech *mech)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
K5_TAILQ_REMOVE(&ctx->negoex_mechs, mech, links);
|
|
Packit Service |
99d1c0 |
release_auth_mech(mech);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Remove all auth mech entries except for mech from ctx->mechs. */
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
negoex_select_auth_mech(spnego_gss_ctx_id_t ctx,
|
|
Packit Service |
99d1c0 |
struct negoex_auth_mech *mech)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
assert(mech != NULL);
|
|
Packit Service |
99d1c0 |
K5_TAILQ_REMOVE(&ctx->negoex_mechs, mech, links);
|
|
Packit Service |
99d1c0 |
release_all_mechs(ctx);
|
|
Packit Service |
99d1c0 |
K5_TAILQ_INSERT_HEAD(&ctx->negoex_mechs, mech, links);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
OM_uint32
|
|
Packit Service |
99d1c0 |
negoex_add_auth_mech(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
|
|
Packit Service |
99d1c0 |
gss_const_OID oid, auth_scheme scheme)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
OM_uint32 major;
|
|
Packit Service |
99d1c0 |
struct negoex_auth_mech *mech;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
mech = calloc(1, sizeof(*mech));
|
|
Packit Service |
99d1c0 |
if (mech == NULL) {
|
|
Packit Service |
99d1c0 |
*minor = ENOMEM;
|
|
Packit Service |
99d1c0 |
return GSS_S_FAILURE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
major = generic_gss_copy_oid(minor, (gss_OID)oid, &mech->oid);
|
|
Packit Service |
99d1c0 |
if (major != GSS_S_COMPLETE) {
|
|
Packit Service |
99d1c0 |
free(mech);
|
|
Packit Service |
99d1c0 |
return major;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
memcpy(mech->scheme, scheme, GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
K5_TAILQ_INSERT_TAIL(&ctx->negoex_mechs, mech, links);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
*minor = 0;
|
|
Packit Service |
99d1c0 |
return GSS_S_COMPLETE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
struct negoex_auth_mech *
|
|
Packit Service |
99d1c0 |
negoex_locate_auth_scheme(spnego_gss_ctx_id_t ctx, const auth_scheme scheme)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct negoex_auth_mech *mech;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
K5_TAILQ_FOREACH(mech, &ctx->negoex_mechs, links) {
|
|
Packit Service |
99d1c0 |
if (GUID_EQ(mech->scheme, scheme))
|
|
Packit Service |
99d1c0 |
return mech;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return NULL;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Prune ctx->mechs to the schemes present in schemes, and reorder them to
|
|
Packit Service |
99d1c0 |
* match its order. */
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
negoex_common_auth_schemes(spnego_gss_ctx_id_t ctx,
|
|
Packit Service |
99d1c0 |
const uint8_t *schemes, uint16_t nschemes)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct negoex_mech_list list;
|
|
Packit Service |
99d1c0 |
struct negoex_auth_mech *mech;
|
|
Packit Service |
99d1c0 |
uint16_t i;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Construct a new list in the order of schemes. */
|
|
Packit Service |
99d1c0 |
K5_TAILQ_INIT(&list);
|
|
Packit Service |
99d1c0 |
for (i = 0; i < nschemes; i++) {
|
|
Packit Service |
99d1c0 |
mech = negoex_locate_auth_scheme(ctx, schemes + i * GUID_LENGTH);
|
|
Packit Service |
99d1c0 |
if (mech == NULL)
|
|
Packit Service |
99d1c0 |
continue;
|
|
Packit Service |
99d1c0 |
K5_TAILQ_REMOVE(&ctx->negoex_mechs, mech, links);
|
|
Packit Service |
99d1c0 |
K5_TAILQ_INSERT_TAIL(&list, mech, links);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Release any leftover entries and replace the context list. */
|
|
Packit Service |
99d1c0 |
release_all_mechs(ctx);
|
|
Packit Service |
99d1c0 |
K5_TAILQ_CONCAT(&ctx->negoex_mechs, &list, links);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Prune ctx->mechs to the schemes present in schemes, but do not change
|
|
Packit Service |
99d1c0 |
* their order. */
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
negoex_restrict_auth_schemes(spnego_gss_ctx_id_t ctx,
|
|
Packit Service |
99d1c0 |
const uint8_t *schemes, uint16_t nschemes)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct negoex_auth_mech *mech, *next;
|
|
Packit Service |
99d1c0 |
uint16_t i;
|
|
Packit Service |
99d1c0 |
int found;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
K5_TAILQ_FOREACH_SAFE(mech, &ctx->negoex_mechs, links, next) {
|
|
Packit Service |
99d1c0 |
found = FALSE;
|
|
Packit Service |
99d1c0 |
for (i = 0; i < nschemes && !found; i++) {
|
|
Packit Service |
99d1c0 |
if (GUID_EQ(mech->scheme, schemes + i * GUID_LENGTH))
|
|
Packit Service |
99d1c0 |
found = TRUE;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (!found)
|
|
Packit Service |
99d1c0 |
negoex_delete_auth_mech(ctx, mech);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
}
|