[krbdev.mit.edu #9018] Bugs while authenticating to azure files
Amandeep Gautam via RT
rt at kerborg-prod-app-1.mit.edu
Tue Jul 27 15:00:54 EDT 2021
<URL: http://kerborg-prod-app-1.mit.edu/rt/Ticket/Display.html?id=9018 >
Sending my response to wider audience as I forgot to add the main mailing
list initially.
Hi Greg,
Thanks for the prompt reply. I think you are right. I mistook
mechListMIC set to GSS_C_NO_BUFFER as an invalid token. These 2 are
different. I added some more logs and here is more detailed information:
In, *init_ctx_cont* the *buf->length* is 9. From *init_ctx_cont*, we call
*get_negTokenResp*, which returns empty *mechListMIC* token with status:
*GSS_S_COMPLETE*.
Progressing in *init_ctx_cont*, we hit the following if-else block
*....*
* } else if (!sc->mech_complete ||*
* (sc->mic_reqd && (sc->ctx_flags &
GSS_C_INTEG_FLAG))) { /* Not obviously done; we may decide
we're done later in * init_ctx_call_init or handle_mic. */*
* *tokflag = CONT_TOKEN_SEND; ret =
GSS_S_COMPLETE; } else { /* mech finished on last
pass and no MIC required, so done. */ *tokflag =
NO_TOKEN_SEND; ret = GSS_S_COMPLETE; }*
* ...*
After returning from here, we return back to
*spnego_gss_init_sec_context* function
(from where we called *init_ctx_cont*). In this function, the handle_mic
call leads to the problem. Code snippet for the call:
* ...*
* negState = ACCEPT_INCOMPLETE; if (spnego_ctx->mech_complete
&& (spnego_ctx->ctx_flags & GSS_C_INTEG_FLAG)) {*
* ret = handle_mic(minor_status,
mechListMIC_in,
(mechtok_out.length != 0),
spnego_ctx, &mechListMIC_out,
&negState, &send_token); if (HARD_ERROR(ret))
goto cleanup;*
* ...*
To be more specific, in *handle_mic* function, I hit the following section:
* ...*
* } else if (sc->mic_reqd && !send_mechtok) { /*
* If the peer sends the final mechanism token, it
* must send the MIC with that token if the * negotiation
requires MICs. */ *negState = REJECT;
*tokflag = ERROR_TOKEN_SEND; return
GSS_S_DEFECTIVE_TOKEN; }*
* ...*
So, I think you were right.
About the suggestions that were made, I think what you are saying is that
(1) is not possible (or very hard). If you can add more details on (2), I
will be happy to make the change and test it.
Basically, I do not understand if the problem is
(a) The assumption that: if we send one, we should receive one? OR
(b) Sending MIC in the first place.
Regards,
Aman
On Mon, Jul 26, 2021 at 4:46 PM Amandeep Gautam <amandeepgautam5 at gmail.com>
wrote:
> Hi Greg,
> Thanks for the prompt reply. I think you are right. I mistook
> mechListMIC set to GSS_C_NO_BUFFER as an invalid token. These 2 are
> different. I added some more logs and here is more detailed information:
>
> In, *init_ctx_cont* the *buf->length* is 9. From *init_ctx_cont*, we call
> *get_negTokenResp*, which returns empty *mechListMIC* token with status:
> *GSS_S_COMPLETE*.
> Progressing in *init_ctx_cont*, we hit the following if-else block
>
>
> *....*
> * } else if (!sc->mech_complete ||*
>
>
>
> * (sc->mic_reqd && (sc->ctx_flags &
> GSS_C_INTEG_FLAG))) { /* Not obviously done; we may decide
> we're done later in * init_ctx_call_init or handle_mic. */*
>
>
>
>
>
>
> * *tokflag = CONT_TOKEN_SEND; ret =
> GSS_S_COMPLETE; } else { /* mech finished on last
> pass and no MIC required, so done. */ *tokflag =
> NO_TOKEN_SEND; ret = GSS_S_COMPLETE; }*
> * ...*
>
> After returning from here, we return back to *spnego_gss_init_sec_context*
> function (from where we called *init_ctx_cont*). In this function, the
> handle_mic call leads to the problem. Code snippet for the call:
>
> * ...*
>
>
>
> * negState = ACCEPT_INCOMPLETE; if
> (spnego_ctx->mech_complete && (spnego_ctx->ctx_flags &
> GSS_C_INTEG_FLAG)) {*
>
>
>
>
>
>
>
> * ret = handle_mic(minor_status,
> mechListMIC_in,
> (mechtok_out.length != 0),
> spnego_ctx, &mechListMIC_out,
> &negState, &send_token); if (HARD_ERROR(ret))
> goto cleanup;*
> * ...*
>
> To be more specific, in *handle_mic* function, I hit the following
> section:
>
> * ...*
>
>
>
>
>
>
>
>
>
>
> * } else if (sc->mic_reqd && !send_mechtok) { /*
> * If the peer sends the final mechanism token, it
> * must send the MIC with that token if the * negotiation
> requires MICs. */ *negState = REJECT;
> *tokflag = ERROR_TOKEN_SEND; return
> GSS_S_DEFECTIVE_TOKEN; }*
> * ...*
>
> So, I think you were right.
>
> About, the suggestions that were made, I think what you are saying is that
> (1) is not possible (or very hard). If you can add more details on (2), I
> will be happy to make the change and test it.
> Basically, I do not understand if the problem is
> (a) The assumption that: if we send one, we should receive one? OR
> (b) Sending MIC in the first place.
>
> Regards,
> Aman
>
>
> On Mon, Jul 26, 2021 at 11:53 AM Greg Hudson via RT <
> rt at kerborg-prod-app-1.mit.edu> wrote:
>
>> Thanks for the comprehensive interop issue report. I have one question:
>>
>> > In function, src/lib/gssapi/spnego/spnego_mech.c: get_negTokenResp we
>> return
>> error code that it is a defective token.
>>
>> This function should only return a defective token error if the packet
>> has a
>> bad length, which does not appear to be the case. Is it possible that the
>> error came from handle_mic() at the first else-if clause?
>>
>> Some background:
>>
>> * RFC 4178 (SPNEGO) section 5 only requires a mechlistMIC exchange if the
>> negotiated mech is not the most-preferred mech of one of the two parties.
>> Otherwise the MIC exchange is optional (unless the negotiated mech has no
>> MIC
>> support, in which case it's impossible).
>>
>> * RFC 4178 section 5 (c) (I) says, for the acceptor processing the final
>> initiator token: "If a mechlistMIC token was included and is correctly
>> verified, GSS_Accept_sec_context() indicates GSS_S_COMPLETE. The output
>> negotiation message contains a mechlistMIC token and an accept_complete
>> state."
>>
>> In this exchange both parties prefer NTLMSSP, so one would expect the MIC
>> exchange to be optional. However, Microsoft imposes an additional
>> constraint
>> for NTLMSSP. This is both observed and documented; [MS-SPNG] Appendix A
>> says:
>>
>> If NTLM authentication is most preferred by the client and the
>> server, and
>> the
>> client includes a MIC in AUTHENTICATE_MESSAGE ([MS-NLMP] section
>> 2.2.1.3), then the mechListMIC field becomes mandatory in order for
>> the
>> authentication to succeed. Windows clients in this case send an NTLM
>> token
>> instead of an SPNEGO token.
>>
>> Accordingly, we have a helper mech_requires_mechlistMIC(), so that
>> NTLMSSP can
>> report that it's behaving in a way that causes a SPNEGO MIC to be
>> required.
>> In our code, the MIC requirement is treated as symmetrical; if we send
>> one, we
>> believe we must receive one, and (following RFC 4178 5.c.I) if we receive
>> one,
>> we send one.
>>
>> From the packet traces it would appear that the Azure server does not
>> believe
>> a MIC is required (i.e. it is not behaving according to [MS-SPNG]
>> Appendix A)
>> and isn't sending a MIC in response to the initiator's MIC (i.e. it it
>> violates RFC 4178 section 5(c)(I)). This apparent misbehavior could be
>> accomodated in two ways:
>>
>> 1. Following the hint in [MS-SPNG] Appendix A, the application could send
>> an
>> NTLM token instead of a SPNEGO token. Generally if a client prefers
>> NTLM, it
>> can only do NTLM, so negotiation isn't required. However, it may be
>> difficult
>> for an application using MIT krb5 to implement this due to the abstraction
>> boundaries; the application doesn't know that the client is only capable
>> of
>> NTLM and the SPNEGO layer can't generate a non-SPNEGO token.
>>
>> 2. In our SPNEGO layer, a true result from mech_requires_mechlistMIC()
>> could
>> cause a MIC token to be generated, but not required from the other party.
>>
>>
>>
More information about the krb5-bugs
mailing list