synta 0.2.5

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# SPNEGO Negotiation Tokens


`synta.spnego` provides classes for the GSSAPI SPNEGO negotiation mechanism (RFC 4178).
It handles both the full GSSAPI-wrapped form (leading `0x60` APPLICATION tag) and the plain
CHOICE form (`0xa0`/`0xa1`).

> **Wire format note:** `GssapiSpnego.asn1` uses `DEFINITIONS IMPLICIT TAGS`.
> All context-tagged fields use IMPLICIT encoding (the universal tag is replaced, not wrapped).

```python
import synta.spnego as spnego
```

## NegTokenInit

Sent by the GSSAPI initiator to propose mechanisms and supply an optional initial token
(RFC 4178 §4.2.1).

```python
class NegTokenInit:
    @staticmethod
    def from_der(data: bytes) -> NegTokenInit: ...
    # Parse a DER-encoded NegTokenInit SEQUENCE.

    mech_types: list[str]       # proposed mechanism OIDs in dot-notation
    req_flags: bytes | None     # context flags bit-string bytes, or None
    mech_token: bytes | None    # initial token for preferred mech, or None
    mech_list_mic: bytes | None # MIC over mechanism list, or None
```

## NegTokenResp

Sent by the GSSAPI acceptor to indicate negotiation state and supply a reply token
(RFC 4178 §4.2.2). Compare `neg_state` against the `NEG_STATE_*` constants.

```python
class NegTokenResp:
    @staticmethod
    def from_der(data: bytes) -> NegTokenResp: ...
    # Parse a DER-encoded NegTokenResp SEQUENCE.

    neg_state: int | None       # NEG_STATE_* constant, or None
    supported_mech: str | None  # selected mechanism OID (dot-notation), or None
    response_token: bytes | None
    mech_list_mic: bytes | None
```

## NegotiationToken

The top-level CHOICE wrapper. `from_der` handles both the full GSSAPI-wrapped form and the
raw CHOICE form.

```python
class NegotiationToken:
    @staticmethod
    def from_der(data: bytes) -> NegotiationToken: ...
    # Accepts 0x60 (GSSAPI-wrapped), 0xa0 (NegTokenInit), or 0xa1 (NegTokenResp).

    variant: str                    # "NegTokenInit" or "NegTokenResp"
    neg_token_init: NegTokenInit | None
    neg_token_resp: NegTokenResp | None
```

## Constants

```python
spnego.NEG_STATE_ACCEPT_COMPLETED   # 0 — negotiation succeeded
spnego.NEG_STATE_ACCEPT_INCOMPLETE  # 1 — more tokens needed
spnego.NEG_STATE_REJECT             # 2 — negotiation rejected
spnego.NEG_STATE_REQUEST_MIC        # 3 — MIC is requested

spnego.SPNEGO_OID  # "1.3.6.1.5.5.2"  (string, not ObjectIdentifier)
```

## Usage

```python
import synta.spnego as spnego

# Parse a GSSAPI SPNEGO token from the network
tok = spnego.NegotiationToken.from_der(gssapi_bytes)
if tok.variant == "NegTokenInit":
    init = tok.neg_token_init
    print("Proposed mechanisms:", init.mech_types)
    if init.mech_token:
        print("Initial token:", len(init.mech_token), "bytes")
else:
    resp = tok.neg_token_resp
    if resp.neg_state == spnego.NEG_STATE_ACCEPT_COMPLETED:
        print("Negotiation complete; mech:", resp.supported_mech)
    elif resp.neg_state == spnego.NEG_STATE_REQUEST_MIC:
        print("MIC requested")
```