In SPNEGO, what does a NegTokenInit offer an acceptor, and what does the reply's negState say?
answer
- preference order is the initiator's policy
- an optimistic guess, sometimes discarded
- four states, only one means finished
- the choice is announced once
- supportedMech appears in the first reply only
basics
~10 sNegTokenInit offers an ordered mechTypes list and often an optimistic mechToken for the first entry. The acceptor's NegTokenResp answers with negState — accept-completed(0), accept-incomplete(1), reject(2) or request-mic(3) — plus supportedMech and responseToken.
solid answer
~40 sA SPNEGO `NegTokenInit` (RFC 4178) carries `mechTypes`, the initiator's mechanism identifiers in preference order, and usually an optimistic `mechToken`: the first-listed mechanism's own first token, sent on the bet that the acceptor will choose it. The acceptor replies with a `NegTokenResp` whose `negState` says where the exchange stands — `accept-completed(0)`, `accept-incomplete(1)`, `reject(2)` or `request-mic(3)` — whose `supportedMech` names the mechanism it selected and appears only in its first reply, and whose `responseToken` carries that mechanism's token. If the acceptor picks a mechanism other than the initiator's first preference, the optimistic token is discarded and the chosen mechanism starts from the beginning, paying the round trip the optimism was meant to save.
code
asn1 · 22 linesNegotiationToken ::= CHOICE {
negTokenInit [0] NegTokenInit,
negTokenResp [1] NegTokenResp
}
NegTokenInit ::= SEQUENCE {
mechTypes [0] MechTypeList,
reqFlags [1] ContextFlags OPTIONAL,
mechToken [2] OCTET STRING OPTIONAL,
mechListMIC [3] OCTET STRING OPTIONAL
}
NegTokenResp ::= SEQUENCE {
negState [0] ENUMERATED {
accept-completed (0),
accept-incomplete (1),
reject (2),
request-mic (3) } OPTIONAL,
supportedMech [1] MechType OPTIONAL,
responseToken [2] OCTET STRING OPTIONAL,
mechListMIC [3] OCTET STRING OPTIONAL
}go deeper
Know that the first token proposes a list of mechanisms and the reply says which one was picked and whether the exchange is finished.
Name the fields of both tokens and the four negotiation states, and explain what the optimistic token buys when the guess is right.
Read a captured negotiation and distinguish 'the acceptor chose a weaker mechanism' from 'the credential was refused', which look identical at the HTTP status line.
Consider what your estate's clients should advertise at all: the list is a policy statement, and every entry on it is a path someone will eventually land on.
## Two token shapes, one negotiation SPNEGO defines a single `NegotiationToken` choice with two arms: the initiator's `NegTokenInit` and everything after it, which is a `NegTokenResp`. The negotiation is short by design — it is trying to get out of the way of the real mechanism as quickly as possible. ## What the initiator offers `NegTokenInit` has four fields and only the first is required: - **`mechTypes`** — the mechanism identifiers the initiator is willing to use, **in preference order**, most preferred first. This ordering is the initiator's whole statement of policy, and the acceptor is free to pick any entry it supports rather than the first. - **`reqFlags`** — an optional legacy field for context flags. It is not the live path for requesting them: the Kerberos mechanism carries the flags an initiator wants in its own token, in the `Authenticator`'s `0x8003` checksum. - **`mechToken`** — the **optimistic token**: the first-listed mechanism's own first token, included so that a single round trip can both propose and begin. - **`mechListMIC`** — an optional checksum over the advertised list, which the initiator can only produce once a mechanism context exists, so on the first token it is usually absent. ## What the acceptor answers `NegTokenResp` answers with a state and, when relevant, material: | Field | Meaning | |---|---| | `negState` | where the negotiation stands | | `supportedMech` | the identifier of the mechanism the acceptor selected; present only in its **first** reply | | `responseToken` | the selected mechanism's own token for this leg | | `mechListMIC` | the checksum over the advertised mechanism list | The four `negState` values are the ones to know by heart: 1. **`accept-completed(0)`** — the negotiation and the mechanism exchange are finished. 2. **`accept-incomplete(1)`** — a further leg is needed; keep going. 3. **`reject(2)`** — no acceptable mechanism, or the exchange has failed. 4. **`request-mic(3)`** — the checksum exchange over the mechanism list is required before completion. Over HTTP `Negotiate` these map onto what the caller sees. `accept-incomplete(1)` shows up as another `401` carrying `WWW-Authenticate: Negotiate <base64>`; `accept-completed(0)` shows up as the resource, possibly with a final token attached; `reject(2)` shows up as a failure that a reader may easily mistake for a wrong password. ## What the optimism is worth The optimistic token is the difference between two shapes of exchange: - **Guessed right.** The acceptor supports the first-listed mechanism, processes the enclosed token immediately, and the negotiation may finish in one further message. - **Guessed wrong.** The acceptor names a different mechanism in `supportedMech`, discards the optimistic token, and the initiator starts the selected mechanism from its first token — so the optimism cost one wasted token and gained nothing. Because the initiator does not know the acceptor's list in advance, the bet is placed on the mechanism it would most like to use, not on the one it thinks is most likely to be supported. ## Misreadings that cost debugging time - **Reading `accept-incomplete(1)` as a refusal.** It is the ordinary continuation state. The refusal is `reject(2)`. - **Expecting `supportedMech` on every reply.** It appears in the acceptor's first reply, where the choice is announced, and not afterwards. - **Assuming the acceptor must honour the ordering.** The order expresses preference; the acceptor selects from what it supports. - **Treating `reqFlags` as how delegation or mutual authentication is requested.** Those requests live in the selected mechanism's own token. - **Believing the negotiation itself carries identity.** Everything that proves anything is inside `mechToken` and `responseToken`. ## Why the field list is worth memorising The fields are how a captured exchange is read. An initial token with three entries in `mechTypes` and an optimistic token tells you what the client was prepared to do; a reply naming the second entry in `supportedMech` tells you the strongest option was not available at the acceptor — which is a very different diagnosis from a credential failure, and the two are otherwise indistinguishable from the HTTP status alone.
- When does the acceptor send `supportedMech`?In its first `NegTokenResp` only. That reply is where the acceptor announces which mechanism it selected from the initiator's `mechTypes`; once both ends know the choice, later replies carry `negState`, `responseToken` and possibly `mechListMIC` without repeating it.
- What happens to an optimistic `mechToken` the acceptor does not want?It is discarded. The acceptor names its chosen mechanism in `supportedMech`, and the initiator starts that mechanism from its own first token. The optimism cost one wasted token and did not save the round trip it was sent to save.
- How does `accept-incomplete(1)` appear to someone watching the HTTP exchange?As another `401` response carrying `WWW-Authenticate: Negotiate <base64>`, rather than the resource. It looks exactly like a rejected credential to anyone counting status codes, which is why the negotiation state inside the token is the thing to read.
saying these in an interview costs you the question
- Thinks the mechTypes order binds the acceptor's choice
- Reads accept-incomplete as a rejected credential
- Believes supportedMech repeats in every reply
- Thinks context flags are requested through reqFlags
- Assumes the optimistic token is always processed