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@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. > > >