[krbdev.mit.edu #9018] Bugs while authenticating to azure files

Amandeep Gautam via RT rt at kerborg-prod-app-1.mit.edu
Wed Jul 28 16:45:39 EDT 2021


<URL: http://kerborg-prod-app-1.mit.edu/rt/Ticket/Display.html?id=9018 >

Gentle ping.

On Tue, Jul 27, 2021 at 11:59 AM Amandeep Gautam <amandeepgautam5 at gmail.com>
wrote:

> 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