skip to content

When a client sets GSS_C_DELEG_FLAG on a Kerberos context, what does the accepting service end up holding?

level: seniorimportance: should knowfreq 37%

answer

  1. the switch lives at the GSS-API layer
  2. the credential rides inside the authenticator
  3. an optional tail on checksum 0x8003
  4. DlgOpt, Dlgth, Deleg
  5. acceptor holds a forwarded ticket-granting ticket

basics

~20 s

A forwarded ticket-granting ticket for the client, plus its session key. GSS_C_DELEG_FLAG makes the initiator pack that credential into the AP-REQ Authenticator's checksum, so the acceptor can afterwards obtain service tickets in the client's name.

solid answer

~40 s

`GSS_C_DELEG_FLAG (1)` is the switch above Kerberos that decides whether a credential travels at all. When `GSS_Init_sec_context` is called with it and the initiator holds a `forwardable(1)` ticket-granting ticket, the mechanism first obtains a *forwarded* ticket-granting ticket from the ticket-granting service, packages it with its session key as a `KRB-CRED` message, and appends it to the `checksum type 0x8003` value carried in the `Authenticator`'s `cksum` field of the `AP-REQ` — in the optional `DlgOpt`, `Dlgth` and `Deleg` fields. `GSS_Accept_sec_context` extracts it, and the acceptor now holds a credential it cannot read but can spend: it can run `TGS-REQ` exchanges whose resulting service tickets name the client in `cname` and `crealm`. Without the flag the acceptor learns who the client is and nothing more.

code

pseudocode · 14 lines
pseudocode
checksum type 0x8003, carried in the AP-REQ Authenticator cksum field

octets  0..3     Lgth    length of Bnd; currently 16
octets  4..19    Bnd     channel-binding value, or 16 zero octets
octets 20..23    Flags   context flags requested by the initiator
                         bit 0 = GSS_C_DELEG_FLAG (1)
                         bit 1 = GSS_C_MUTUAL_FLAG (2)
                         bit 3 = GSS_C_SEQUENCE_FLAG (8)

-- the three fields below appear ONLY when delegating
octets 24..25    DlgOpt  delegation option identifier, value 1
octets 26..27    Dlgth   length in octets of the Deleg field
octets 28..      Deleg   a KRB-CRED carrying the forwarded
                         ticket-granting ticket and its session key

go deeper

for a junior

Recall that a service can be handed the right to act as the user, that this is a deliberate request rather than a side effect of logging in, and that the user's password is never what travels.

for a middle

Explain the two preconditions — the GSS-API flag being requested and the initiator holding a forwardable ticket-granting ticket — and that the credential travels inside the AP-REQ rather than in a message of its own.

for a senior

Diagnose the silent case: the flag was requested, no credential arrived, and the context established anyway. Name the field that would have carried it and check the flags the acceptor actually got back.

for a principal

Treat delegation as an estate-wide default to be argued about, not a per-connection convenience. Weigh what a compromised middle tier gains against the work of having back ends accept the middle tier's own principal instead.

## The switch sits above Kerberos, not inside it Kerberos itself has no notion of an application deciding to delegate. It has `forwardable(1)`, which says forwarding is *permitted*, and it has the machinery to issue a forwarded ticket-granting ticket when asked. What decides whether a particular connection actually carries a credential is a **GSS-API context flag**, `GSS_C_DELEG_FLAG (1)`, requested by the initiator when it calls `GSS_Init_sec_context`. That separation matters in practice. Two conditions must both hold before anything is delegated: - the initiator must **ask**, by setting `GSS_C_DELEG_FLAG`; and - the initiator must **hold a `forwardable(1)` ticket-granting ticket**, or there is nothing the ticket-granting service will forward. When only one holds, the context still establishes and the acceptor still learns who the client is — it simply gets no credential. The `GSS_Accept_sec_context` result reports which flags were actually satisfied, which is the honest place to check rather than assuming the request succeeded. ## What the initiator does, in order 1. Obtain a **forwarded ticket-granting ticket** from the ticket-granting service in a `TGS-REQ`, asking for the `krbtgt` service of its own realm and requesting the forwarded option; the reply's ticket carries `forwarded(2)`, and may carry the acceptor's network address in `caddr` or no addresses at all. 2. Wrap that ticket and its session key in a **`KRB-CRED`** message, encrypted so that only the acceptor of this context can open it. 3. Build the `Authenticator` for the `AP-REQ` and place, in its `cksum` field, a value of **`checksum type 0x8003`** whose optional tail carries the `KRB-CRED`. 4. Send the `AP-REQ`. The delegated credential rides **inside** it; there is no separate delegation message. ## Where the credential rides The `0x8003` checksum value is a fixed-layout octet string, not a hash in the ordinary sense — it is the structure the Kerberos V5 GSS-API mechanism uses to carry channel bindings, context flags and, optionally, a credential: - `Lgth` — the length of the binding field, currently 16. - `Bnd` — the channel-binding value, or sixteen zero octets when no bindings are used. - `Flags` — the context flags the initiator requested; bit 0 is `GSS_C_DELEG_FLAG (1)`, bit 1 is `GSS_C_MUTUAL_FLAG (2)`, bit 3 is `GSS_C_SEQUENCE_FLAG (8)`. - `DlgOpt`, `Dlgth`, `Deleg` — **present only when delegating**: an option identifier, a length, and the `KRB-CRED` itself. So the entire delegation decision is visible in one field of one message, and its absence is equally visible: a context with no trailing `Deleg` field delegated nothing. | Context flag | What the initiator is asking for | What the acceptor gains | |---|---|---| | `GSS_C_DELEG_FLAG (1)` | send a usable credential for the client | the ability to act as the client downstream | | `GSS_C_MUTUAL_FLAG (2)` | prove the acceptor's own identity in return | nothing downstream; the initiator gains the `AP-REP` | | `GSS_C_SEQUENCE_FLAG (8)` | detect reordered per-message tokens | ordering guarantees on `GSS_GetMIC` and `GSS_Wrap` output | ## What the acceptor holds afterwards, and what it does not What it holds is a **credential**, not a copy of a secret: - The forwarded ticket-granting ticket is sealed under the **`krbtgt` key**. The acceptor cannot read the client name, flags or `renew-till` inside its `enc-part`. - The **session key** arrives alongside it in the `KRB-CRED`, which is what makes the ticket spendable: the acceptor can build its own `Authenticator` and run a `TGS-REQ`. - The service tickets that come back name the **client** in `cname` and `crealm`. The back-end service sees the user, applies the user's own rights, and has no protocol-level way to tell that a middle tier asked. - The client's **long-term key never travels**. Nothing in this exchange discloses the password or the key `string-to-key` derived from it. What the acceptor does **not** get is any limit. This is unconstrained forwarding: the credential is good for whatever the ticket-granting service will issue, for as long as the forwarded ticket-granting ticket lives, including its renewal window. That is the property the constrained and resource-based models were introduced to remove, and it is why the flag is a deployment decision rather than a default. Declining to delegate costs the acceptor much less than people expect. Identity still comes from the `AP-REQ` and its `Authenticator`; the acceptor still knows exactly who called. It simply has to reach downstream services as **its own service principal**, which for most back ends is the correct design anyway.

  • What does the acceptor have to do to use a delegated credential it has received?
    Import it as a credential for the client principal, then run an ordinary `TGS-REQ` with it exactly as the client would: present the forwarded ticket-granting ticket as `pa-tgs-req (padata-type 1)`, authenticate with the session key that arrived in the `KRB-CRED`, and receive a service ticket whose `cname` and `crealm` are the client's.
  • Does an acceptor that declines delegation lose the ability to know who the client is?
    No. Identity comes from the `AP-REQ` and its `Authenticator`, which are present either way. Without `GSS_C_DELEG_FLAG` the acceptor knows the client's `cname` and `crealm` and holds a session key for the context; it simply has to reach downstream services with its own service principal's rights.
  • The initiator set GSS_C_DELEG_FLAG but the acceptor got no credential. What is the likely cause?
    The initiator's own ticket-granting ticket was not marked `forwardable(1)`, so the ticket-granting service had nothing to forward. The context still establishes, because delegation is a request rather than a requirement — which is why the flags actually returned by `GSS_Accept_sec_context` must be checked rather than assumed.

saying these in an interview costs you the question

  • Says the client's long-term key or password is sent to the service.
  • Thinks every Kerberos context delegates credentials by default.
  • Claims the delegated credential arrives in its own message after the AP-REQ.
  • Confuses GSS_C_DELEG_FLAG with GSS_C_MUTUAL_FLAG, which only asks for an AP-REP.
  • Believes the acceptor merely learns the user's name, not a usable credential.