gss: pass mechanism error tokens through SPNEGO

Fix for issue #486 based on a patch by Nico Williams.

A GSS-API acceptor can return an error token to be sent to the initiator. Our
SPNEGO implementation discarded these when sending a SPNEGO reject response.
This patch fixes the SPNEGO acceptor to convey those in the SPNEGO response.

The SPNEGO initiator is also updated to not bail out early on receiving a
SPNEGO reject response from the acceptor, but instead pass the response token
(if any) to gss_init_sec_context(). A reject response with no response token
will continue to return an error.
This commit is contained in:
Luke Howard
2020-04-22 09:35:14 +10:00
parent dfb1e6fcf8
commit 8d19f3f47f
2 changed files with 47 additions and 17 deletions

View File

@@ -35,10 +35,12 @@
static OM_uint32
send_reject (OM_uint32 *minor_status,
gss_buffer_t mech_token,
gss_buffer_t output_token)
{
NegotiationToken nt;
size_t size;
heim_octet_string responseToken;
nt.element = choice_NegotiationToken_negTokenResp;
@@ -50,6 +52,13 @@ send_reject (OM_uint32 *minor_status,
*(nt.u.negTokenResp.negState) = reject;
nt.u.negTokenResp.supportedMech = NULL;
nt.u.negTokenResp.responseToken = NULL;
if (mech_token != GSS_C_NO_BUFFER && mech_token->value != NULL) {
responseToken.length = mech_token->length;
responseToken.data = mech_token->value;
nt.u.negTokenResp.responseToken = &responseToken;
} else
nt.u.negTokenResp.responseToken = NULL;
nt.u.negTokenResp.mechListMIC = NULL;
ASN1_MALLOC_ENCODE(NegotiationToken,
@@ -513,7 +522,7 @@ acceptor_complete(OM_uint32 * minor_status,
ret = _gss_spnego_verify_mechtypes_mic(minor_status, ctx, mic);
if (ret) {
if (*get_mic)
send_reject(minor_status, output_token);
send_reject(minor_status, GSS_C_NO_BUFFER, output_token);
if (buf.value)
free(buf.value);
return ret;
@@ -888,12 +897,11 @@ acceptor_continue
input_chan_bindings,
&obuf,
delegated_cred_handle);
if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
mech_output_token = &obuf;
}
mech_output_token = &obuf;
if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
free_NegotiationToken(&nt);
send_reject(&junk, output_token);
send_reject(&junk, mech_output_token, output_token);
gss_release_buffer(&junk, mech_output_token);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return ret;
}