Partial

RFC 8907 - The Terminal Access Controller Access-Control System Plus (TACACS+) Protocol

Every requirement this repository extracted from RFC 8907, the tests bound to it, and what a reader has verified about them. This summary is enrolled and gated by ./le rfc check.

Overview

Positive

what Ze has

Tested both ways80.4%45 of 56 gated MUSTs

a positive test proves Ze does what the requirement demands and a negative one proves it refuses what the requirement forbids

One polarity plus reason5.4%3 of 56 gated MUSTs

the requirement admits no counter-case, so one polarity plus a recorded reason is the whole proof available for it

One polarity, unexcused0.0%0 of 56 gated MUSTs

one direction is tested, the other is neither tested nor excused, and nothing states which

Partial proof; remaining gap0.0%0 of 56 gated MUSTs

scoped tests exist; the remaining obligation is unmet or unproven, with zero whole-requirement credit

No test at all0.0%0 of 56 gated MUSTs

no test carries the requirement id, whether or not a gap states why

Proven by a recorded break69.1%105 of 152 tagged units

a red was observed once under a recorded procedure, and the unit, the claim and the producer it rested on still hash to what was recorded. The break is not re-run. A test pair is not a proof until one has been observed

Neutral

measures that are neither good news nor bad

Gated MUSTs56of 59 this summary declares

MUST-level requirements the gate HOLDS. A population, not a result: the shares beside it are what says how Ze stands

Out of scope8of 56 gated MUSTs

an obligation that does not bind Ze. A {not-applicable} annotation says it never bound; a {feature-declined} annotation says its condition is an optional feature Ze does not offer, and quotes the RFC sentence that makes it optional. Scope, not coverage: it stays in the denominator every share on this page is taken over

Not applicable3.6%2 of 56 gated MUSTs

a {not-applicable} annotation says the obligation does not bind Ze, so no test is owed for it. It stays in the denominator every share here is taken over

Met below Ze0.0%0 of 56 gated MUSTs

a {lower-layer} annotation says a layer under Ze performs the behavior, on state Ze installs into that layer, and names the producer that installs it. The obligation binds Ze and is met; Ze proves none of it, because its own boundary carries no value the behavior reads

Optional feature declined10.7%6 of 56 gated MUSTs

a {feature-declined} annotation says the obligation is conditional on a feature the RFC makes optional and Ze does not offer, and it quotes the sentence that makes it optional. The condition is false, so nothing is owed and nothing is missing. It stays in the denominator every share here is taken over

The 8 shares marked as a part above are the whole of the 56 gated MUSTs: they add to 100%. Proven by a recorded break is a share of TAGGED UNITS, a different population, so it is not one of them.

How to read the colors

A color names what the measure MEANS, not how well Ze scores on it. Green is a good outcome at any value, red is a bad one, and neither a population nor a scope count is an outcome, so both take no color. The number under the label is what says how far Ze has got.

CardTone hereWhy that color
Gated MUSTs neutral no color: a population is a scale, and a larger one is neither good news nor bad. It is the accounting total
Out of scope neutral no color: an obligation that never bound Ze is neither an achievement nor a failure, and counting it either way would be a claim
Tested both ways ok green at every value: a test pair is the outcome this gate exists to produce, and the share under the label is what says how far Ze has got
One polarity plus reason ok green at every value: where no counter-case exists, one polarity IS the complete answer, and a recorded reason is what the gate demands beside it
One polarity, unexcused ok green at zero, RED above it: half a proof with no reason for the other half
Partial proof; remaining gap ok green at zero, RED above it: a tested clause cannot prove the whole requirement
No test at all ok green at zero, RED above it: a binding obligation nothing exercises is a claim with nothing behind it, whether or not a reason is stated
Not applicable neutral no color: an obligation that never bound Ze is neither an achievement nor a failure, and counting it either way would be a claim
Met below Ze neutral no color: an obligation met below Ze is neither a test Ze wrote nor work Ze owes, and the two green shares above are what says how much Ze proves itself
Optional feature declined neutral no color: an obligation whose condition Ze never meets is neither an achievement nor a failure. The absent FEATURE is disclosed on the RFC's own status row, as an implementation gap a later scope decision can revisit
Proven by a recorded break ok green at every value: an observed break is the outcome the discrimination gate exists to produce. The denominator is TAGGED UNITS, not obligations, so this share is not one of the parts above
Audit verdicts warn RED on the first weak, wrong or unimplemented verdict, amber while a verdict is no longer current or a gated MUST is unjudged, green when every one is judged sound and current

At a glance

FieldValue
Public status Partial
Enrolment Enrolled
Requirements 59
Gated MUST-level 56
Not applicable, so out of scope 2
Declared gaps 0
Declared gaps a test demonstrates 0
Gated with no test 0
Nightly-only evidence 0
Test tags 152
Tagged units 152
Recorded audit verdicts 48
Discrimination records 105
Summary rfc/short/rfc8907.md
Requirement shard rfc/requirements/rfc8907.md
RFC text rfc/full/rfc8907.txt

Enrolment

Enrolled: Ze implements a TACACS+ client for management AAA. The 2026-09-21 extraction walk expanded the original requirement list; the compliance checklist below is the requirement inventory, and tagged tests name their producers. Verification and discrimination must be rerun after the current implementation changes before publishing a conformance count.

What the public ledger says

Status: Partial

What the ledger says is covered
  • PAP login followed by shell-session privilege authorization
  • printable-ASCII fields and UsernameCasePreserved usernames
  • exact decrypted lengths
  • ordered ERROR failover
  • mandatory command arguments
  • command accounting and negotiated single-connect reuse.
What the ledger says remains Current implementation changes await test and discrimination runs. On 2026-09-21 the owner selected tacacs_methods='Keep PAP authentication': no ASCII interactive, CHAP, MS-CHAP v1/v2 or ENABLE authentication workflows. The conditional method rows retain that selection and their source text. Section 10.5 also includes deployment obligations that a TCP reachability check cannot establish.

Coverage

BucketCountWhat it counts
Positive and negative tests 45 one part of the gated population
Annotated (including scoped evidence) 11 one part of the gated population
One polarity only 0 one part of the gated population
No test and no annotation 0 one part of the gated population
Partial proof; remaining gap (subset of annotated; zero whole-requirement credit) 0 an overlay: each of these is also counted by the part it falls in
Evidence that runs nightly only 0 an overlay: each of these is also counted by the part it falls in
Derived from other rows 1 outside the gated population: each asserts nothing and derives its state from the rows it names, which the parts above already count
Gated MUST-level requirements56every gated MUST falls in exactly one bucket above

Positive and negative tests (45): RFC8907-4-1, RFC8907-4-2, RFC8907-4-4, RFC8907-4.6-1, RFC8907-7-1, RFC8907-7-2, RFC8907-10-2, RFC8907-10.5.2-1, RFC8907-6-1, RFC8907-3.7-1, RFC8907-3.7-2, RFC8907-4.1-1, RFC8907-4.1-2, RFC8907-4.1-3, RFC8907-4.3-1, RFC8907-4.3-2, RFC8907-4.3-3, RFC8907-4.4-1, RFC8907-4.4-2, RFC8907-4.4-3, RFC8907-5.1-1, RFC8907-5.4.2.2-1, RFC8907-5.4.2.2-2, RFC8907-5.4.2.6-2, RFC8907-5.4.3-1, RFC8907-6.1-1, RFC8907-6.1-2, RFC8907-6.2-1, RFC8907-6.2-2, RFC8907-6.2-3, RFC8907-7.2-1, RFC8907-8-1, RFC8907-8.1-1, RFC8907-8.1-2, RFC8907-8.2-1, RFC8907-8.2-2, RFC8907-8.3-1, RFC8907-8.3-2, RFC8907-8.3-3, RFC8907-8.3-4, RFC8907-8.3-5, RFC8907-10.5.1-1, RFC8907-10.5.1-2, RFC8907-10.5.4-1, RFC8907-x-2

Annotated (including scoped evidence) (11): RFC8907-4-3, RFC8907-4-5, RFC8907-5-1, RFC8907-10-1, RFC8907-5.4-1, RFC8907-5.4-2, RFC8907-5.4.2.3-1, RFC8907-5.4.2.4-1, RFC8907-5.4.2.5-1, RFC8907-5.4.2.6-1, RFC8907-4.6-2

Derived from other rows (1): RFC8907-10.5-1

Requirements

RequirementLevelSectionTests
RFC8907-4-1This is the major TACACS+ version number. TAC_PLUS_MAJOR_VER := 0xc (§4.1)
MUST 4.1
RFC8907-4-2TACACS+ clients only send packets containing odd sequence numbers, and TACACS+ servers only send packets containing even sequence numbers. (§4.1)
MUST 4.1
RFC8907-4-3This number MUST be generated by a cryptographically strong random number generation method. (§4, Session Lifecycle)
MUST 4
positiveunit/verifyTestRandomSessionIDDistinct
negativeno testno negative test

{single-polarity}: the session id is drawn from crypto/rand (internal/component/tacacs/client.go:497-503) with no predictable/reject path

RFC8907-4-4The Id for this TACACS+ session. This field does not change for the duration of the TACACS+ session. (§4.1)
MUST 4.1
RFC8907-4-5All length values are unsigned and in network byte order. (§4.1)
MUST 4.1
negativeno testno negative test

{single-polarity}: multi-octet header fields (session_id, length) are written and read with binary.BigEndian at internal/component/tacacs/packet.go:75-76 and 90-91; the marshal/unmarshal round-trip is symmetric with no independent little-endian oracle, so a negative would only test a different codec

RFC8907-4.6-1After a packet body is de-obfuscated, the lengths of the component values in the packet are summed. If the sum is not identical to the cleartext datalength value from the header, the packet MUST be discarded and an ERROR signaled. (§4.5, Data Obfuscation)
MUST 4.5
RFC8907-5-1The sequence number must never wrap, i.e., if the sequence number 2^(8)-1 is ever reached, that session must terminate and be restarted with a sequence number of 1. (§4.1, Packet Header; maximum 255, not 254)
MUST 4.1
positiveno testno positive test
negativeno testno negative test

{not-applicable}: on 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`; internal/component/tacacs/client.go::Authenticate calls NewPAPAuthenStart and trySend emits sequence 1 and accepts only reply sequence 2. Section 5.4.2.2 requires one START and one REPLY for PAP, so no reachable authentication exchange approaches 255 or wraps; the separate initial/reply sequence tests remain applicable

RFC8907-7-1This holds bitmapped flags. Valid values are: TAC_PLUS_ACCT_FLAG_START := 0x02 TAC_PLUS_ACCT_FLAG_STOP := 0x04 TAC_PLUS_ACCT_FLAG_WATCHDOG := 0x08 (§7.1)
MUST NOT 7.1
RFC8907-7-2The START and STOP flags are mutually exclusive. (§7.2)
MUST 7.2
RFC8907-10-1Clients MUST be implemented in a way that requires explicit configuration to enable the use of TAC_PLUS_UNENCRYPTED_FLAG. (§10.5.2)
MUST 10.5.2
positiveunit/verifyTestPacketMarshalRoundTrip
negativeno testno negative test

{single-polarity}: ze exposes no configuration that enables TAC_PLUS_UNENCRYPTED_FLAG: the schema declares no leaf for it and makes the shared secret mandatory (internal/component/tacacs/yang/ze-tacacs-conf.yang), the only request flag any producer sets is FlagSingleConnect (internal/component/tacacs/client.go trySend), and (*Packet).MarshalInto (internal/component/tacacs/packet.go) refuses a marshal with no shared secret instead of falling back to an unencrypted send, so there is no enabled state to drive a negative against

RFC8907-10-2TACACS+ clients MUST NOT set TAC_PLUS_UNENCRYPTED_FLAG. (§10, Security)
MUST NOT 10
RFC8907-10.5.2-1When a TACACS+ client receives responses from servers where: * the response packet was received from the server configured with a shared key, but the packet has TAC_PLUS_UNENCRYPTED_FLAG set, and * the response packet was received from the server configured not to use obfuscation, but the packet has TAC_PLUS_UNENCRYPTED_FLAG not set, the TACACS+ client MUST close the TCP session, and process the response in the same way that a TAC_PLUS_AUTHEN_STATUS_FAIL (authentication sessions) or TAC_PLUS_AUTHOR_STATUS_FAIL (authorization sessions) was received. (§10.5.2, Connections and Obfuscation)
MUST 10.5.2
RFC8907-6-1Mandatory arguments require that the receiving side can handle the argument, that is, its implementation and configuration includes the details of how to act on it. If the client receives a mandatory argument that it cannot handle, it MUST consider the authorization to have failed. (§6.1)
MUST 6.1
RFC8907-3.7-1Usernames MUST be encoded and handled using the UsernameCasePreserved Profile specified in [RFC8265]. (§3.7, Treatment of Text Strings)
MUST 3.7
RFC8907-3.7-2All other text fields in TACACS+ MUST be treated as printable byte arrays of US-ASCII as defined by [RFC0020]. The term "printable" used here means the fields MUST exclude the "Control Characters" defined in Section 5.2 of [RFC0020]. (§3.7, Treatment of Text Strings)
MUST 3.7
RFC8907-4.1-1To signal that any variable-length data fields are unused, the corresponding length values are set to zero. Such fields MUST be ignored, and treated as if not present. (§4.1, The TACACS+ Packet Header)
MUST 4.1
RFC8907-4.1-2The first packet in a session MUST have the sequence number 1, and each subsequent packet will increment the sequence number by one. (§4.1, The TACACS+ Packet Header)
MUST 4.1
RFC8907-4.1-3All other bits MUST be ignored when reading, and SHOULD be set to zero when writing. (§4.1, The TACACS+ Packet Header)
MUST 4.1
RFC8907-4.3-1The client MUST NOT send a second packet on a connection until single-connect status has been established. (§4.3, Single Connection Mode)
MUST NOT 4.3
RFC8907-4.3-2No provision is made for changing Single Connection Mode after the first two packets; the client and server MUST ignore the flag after the second packet on a connection. (§4.3, Single Connection Mode)
MUST 4.3
RFC8907-4.3-3The client MUST accommodate such closures on a TCP session even after Single Connection Mode has been established. (§4.3, Single Connection Mode)
MUST 4.3
RFC8907-4.4-1The server responds with an ERROR to indicate that the processing of the request did not complete. The client cannot apply the result, and it MUST behave as if the server could not be connected to. (§4.4, Session Completion)
MUST 4.4
RFC8907-4.4-2If Single Connection Mode was enabled, but an ERROR occurred due to connection issues (such as an incorrect secret (see Section 4.5)), then any further new sessions MUST NOT be accepted on the connection. (§4.4, Session Completion)
MUST NOT 4.4
RFC8907-4.4-3Once all active sessions are completed, then the connection MUST be closed. (§4.4, Session Completion)
MUST 4.4
RFC8907-5.1-1The username is optional in this packet, depending upon the class of authentication. If it is absent, the client MUST set user_len to 0. (§5.1, The Authentication START Packet Body)
MUST 5.1
RFC8907-5.4-1When the REPLY status equals TAC_PLUS_AUTHEN_STATUS_GETDATA, TAC_PLUS_AUTHEN_STATUS_GETUSER, or TAC_PLUS_AUTHEN_STATUS_GETPASS, authentication continues and the server SHOULD provide server_msg content for the client to prompt the user for more information. The client MUST then return a CONTINUE packet containing the requested information in the user_msg field. (§5.4, Description of Authentication Process)
MUST 5.4
positiveno testno positive test
negativeno testno negative test

{feature-declined}: "The entire exchange MUST consist of a single START packet and a single REPLY."; the PAP-specific rule is §5.4.2.2, which also restricts the reply to PASS, FAIL or ERROR. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding ASCII interactive workflows. internal/component/tacacs/client.go::Authenticate produces PAP through NewPAPAuthenStart, and validateReplyStatus rejects GETDATA/GETUSER/GETPASS rather than entering an interactive exchange; this is a selected method boundary, not a server-only obligation

RFC8907-5.4-2If the information being requested by the server from the client is sensitive, then the server should set the TAC_PLUS_REPLY_FLAG_NOECHO flag. When the client queries the user for the information, the response MUST NOT be reflected in the user interface as it is entered. (§5.4, Description of Authentication Process)
MUST NOT 5.4
positiveno testno positive test
negativeno testno negative test

{feature-declined}: "When the client queries the user for the information, the response MUST NOT be reflected in the user interface as it is entered."; this rule is conditional on interactive prompting. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding ASCII interaction. internal/component/tacacs/client.go::Authenticate receives an already supplied username/password through aaa.AuthRequest and never prompts in response to a TACACS+ reply

RFC8907-5.4.2.2-1The entire exchange MUST consist of a single START packet and a single REPLY. (§5.4.2.2, PAP Login)
MUST 5.4.2.2
RFC8907-5.4.2.2-2The START packet MUST contain a username and the data field MUST contain the PAP ASCII password. (§5.4.2.2, PAP Login)
MUST 5.4.2.2
RFC8907-5.4.2.3-1The entire exchange MUST consist of a single START packet and a single REPLY. The START packet MUST contain the username in the user field, and the data field is a concatenation of the PPP id, the challenge, and the response. (§5.4.2.3, CHAP Login)
MUST 5.4.2.3
positiveno testno positive test
negativeno testno negative test

{feature-declined}: "The START packet MUST contain the username in the user field, and the data field is a concatenation of the PPP id, the challenge, and the response."; §5.4.2.3 scopes this construction to authen_type TAC_PLUS_AUTHEN_TYPE_CHAP. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding CHAP. internal/component/tacacs/client.go::Authenticate accepts username/password and uses NewPAPAuthenStart; no product CHAP challenge/response workflow exists

RFC8907-5.4.2.4-1The entire exchange MUST consist of a single START packet and a single REPLY. The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response. (§5.4.2.4, MS-CHAP v1 Login)
MUST 5.4.2.4
positiveno testno positive test
negativeno testno negative test

{feature-declined}: "The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response."; §5.4.2.4 scopes this construction to authen_type TAC_PLUS_AUTHEN_TYPE_MSCHAP. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding MS-CHAP v1. internal/component/tacacs/client.go::Authenticate accepts username/password and uses NewPAPAuthenStart; no product MS-CHAP v1 challenge/response workflow exists

RFC8907-5.4.2.5-1The entire exchange MUST consist of a single START packet and a single REPLY. The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response. (§5.4.2.5, MS-CHAP v2 Login)
MUST 5.4.2.5
positiveno testno positive test
negativeno testno negative test

{feature-declined}: "The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response."; §5.4.2.5 scopes this construction to authen_type TAC_PLUS_AUTHEN_TYPE_MSCHAPV2. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding MS-CHAP v2. internal/component/tacacs/client.go::Authenticate accepts username/password and uses NewPAPAuthenStart; no product MS-CHAP v2 challenge/response workflow exists

RFC8907-5.4.2.6-1In order to readily distinguish "ENABLE" requests from other types of request, the value of the authen_service field MUST be set to TAC_PLUS_AUTHEN_SVC_ENABLE when requesting an ENABLE. (§5.4.2.6, Enable Requests)
MUST 5.4.2.6
positiveno testno positive test
negativeno testno negative test

{feature-declined}: "The exchange MAY consist of multiple messages while the server collects the information it requires in order to allow changing the principal's privilege level."; §5.4.2.6 defines an ENABLE privilege-change workflow, and the service rule applies when requesting an ENABLE. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding ENABLE workflows. internal/component/tacacs/authen.go::NewPAPAuthenStart sets the LOGIN service for the management password callback; it does not request a privilege change. The separate prohibition on using ENABLE for other operations remains tested

RFC8907-5.4.2.6-2It MUST NOT be set to this value when requesting any other operation. (§5.4.2.6, Enable Requests)
MUST NOT 5.4.2.6
RFC8907-5.4.3-1If a client does not implement the TAC_PLUS_AUTHEN_STATUS_RESTART option, then it MUST process the response as if the status was TAC_PLUS_AUTHEN_STATUS_FAIL. (§5.4.3, Aborting an Authentication Session)
MUST 5.4.3
RFC8907-6.1-1The user_len MUST indicate the length of the user field, in bytes. (§6.1, The Authorization REQUEST Packet Body)
MUST 6.1
RFC8907-6.1-2An argument name MUST NOT contain either of the separators. (§6.1, The Authorization REQUEST Packet Body)
MUST NOT 6.1
RFC8907-6.2-1If the status equals TAC_PLUS_AUTHOR_STATUS_PASS_ADD, then the arguments specified in the request are authorized and the arguments in the response MUST be applied according to the rules described above. (§6.2, The Authorization REPLY Packet Body)
MUST 6.2
RFC8907-6.2-2If the status equals TAC_PLUS_AUTHOR_STATUS_PASS_REPL, then the client MUST use the authorization argument-value pairs (if any) in the response instead of the authorization argument- value pairs from the request. (§6.2, The Authorization REPLY Packet Body)
MUST 6.2
RFC8907-6.2-3If the status equals TAC_PLUS_AUTHOR_STATUS_FAIL, then the requested authorization MUST be denied. (§6.2, The Authorization REPLY Packet Body)
MUST 6.2
RFC8907-7.2-1The STOP flag MUST NOT be set in conjunction with the WATCHDOG flag. (§7.2, The Accounting REPLY Packet Body)
MUST NOT 7.2
RFC8907-8-1Clients MUST use these arguments when supporting the corresponding use cases. (§8, Argument-Value Pairs)
MUST 8
RFC8907-8.1-1TACACS+ implementations MUST verify that they can accommodate the lengths of numeric arguments before attempting to process them. If the length cannot be accommodated, then the argument MUST be regarded as not handled and the logic in "Authorization" (Section 6.1) regarding the processing of arguments MUST be applied. (§8.1)
MUST 8.1
RFC8907-8.1-2Absolute date/times are specified in seconds since the epoch, 12:00am, January 1, 1970. The time zone MUST be UTC unless a time zone argument is specified. (§8.1)
MUST 8.1
RFC8907-8.2-1Specifying a service argument indicates that this is a request for authorization or accounting of that service. For example: "shell", "tty-server", "connection", "system" and "firewall"; others may be chosen for the required application. This argument MUST always be included. (§8.2)
MUST 8.2
RFC8907-8.2-2The "cmd" argument MUST be specified if service equals "shell". (§8.2, Authorization Arguments)
MUST 8.2
RFC8907-8.3-1The following arguments are defined for TACACS+ accounting only. They MUST precede any argument-value pairs that are defined in "Authorization" (Section 6). (§8.3)
MUST 8.3
RFC8907-8.3-2Start and stop records for the same event MUST have matching task_id argument values. (§8.3, Accounting Arguments)
MUST 8.3
RFC8907-8.3-3The client MUST ensure that active task_ids are not duplicated; a client MUST NOT reuse a task_id in a start record until it has sent a stop record for that task_id. (§8.3, Accounting Arguments)
MUST NOT 8.3
RFC8907-8.3-4To support this mode of operation, TACACS+ client devices MUST be configured to send an accounting start packet for every command entered, irrespective of how the commands were authorized. (§8.3, Accounting Arguments)
MUST 8.3
RFC8907-8.3-5These "Command Accounting" packets MUST include the "service" and "cmd" arguments, and if needed, the "cmd-arg" arguments detailed in Section 8.2. (§8.3, Accounting Arguments)
MUST 8.3
RFC8907-10.5-1New implementations, and upgrades of current implementations, MUST implement these recommendations. (§10.5, TACACS+ Best Practices)
MUST 10.5
positiveno testno positive test
negativeno testno negative test

{rollup}: RFC8907-10.5.1-1, RFC8907-10.5.1-2, RFC8907-10.5.2-1, RFC8907-10.5.4-1; Section 10.5 makes "these recommendations" of Sections 10.5.1 to 10.5.4 mandatory for new implementations, and those four rows carry the client-side recommendations the checklist gates; the MUSTs of Sections 10.5.3 and 10.5.5 bind TACACS+ servers, a role ze does not fill

derived: met

RFC8907-10.5.1-1TACACS+ servers and clients MUST treat shared secrets as sensitive data to be managed securely, as would be expected for other sensitive data such as identity credential information. (§10.5.1, Shared Secrets)
MUST 10.5.1
RFC8907-10.5.1-2* TACACS+ servers and clients MUST support shared keys that are at least 32 characters long. (§10.5.1, Shared Secrets)
MUST 10.5.1
RFC8907-10.5.4-1The cost of the flexibility is that administrators and implementers MUST ensure that the argument and value pairs shared between the clients and servers have consistent interpretation. (§10.5.4, Authorization)
MUST 10.5.4
RFC8907-4.6-2A request MUST be dropped if TAC_PLUS_UNENCRYPTED_FLAG is set to true. (§4.5, Data Obfuscation; stable historical ID)
MUST 4.5
positiveno testno positive test
negativeno testno negative test

{not-applicable}: this request-receiver obligation binds a TACACS+ server. Ze implements the management AAA client, not a TACACS+ server; the client's separate obfuscation and reply-validation obligations remain applicable

RFC8907-x-1The client should manage connections and handle the case of a server that establishes a connection but does not respond. The exact behavior is implementation specific. It is recommended that the client close the connection after a configurable timeout. (§4.4)
SHOULD 4.4
positiveno testno positive test
negativeno testno negative test
RFC8907-x-2This document deprecates the redirection mechanism using the TAC_PLUS_AUTHEN_STATUS_FOLLOW option, which was included in "The Draft". As part of this process, the secret key for a new server was sent to the client. This public exchange of secret keys means that once one session is broken, it may be possible to leverage that key to attacking connections to other servers. This mechanism MUST NOT be used in modern deployments. It MUST NOT be used outside a secured deployment. (§10.2)
MUST NOT 10.2
RFC8907-6-2Optional arguments are ones that may be disregarded by either client or server. (§6.1)
MAY 6.1
positiveno testno positive test
negativeno testno negative test

Gaps and untested MUSTs

RequirementStateReason
RFC8907-5-1 The sequence number must never wrap, i.e., if the sequence number 2^(8)-1 is ever reached, that session must terminate and be restarted with a sequence number of 1. (§4.1, Packet Header; maximum 255, not 254) no test no test carries this requirement id; annotated {not-applicable}: on 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`; internal/component/tacacs/client.go::Authenticate calls NewPAPAuthenStart and trySend emits sequence 1 and accepts only reply sequence 2. Section 5.4.2.2 requires one START and one REPLY for PAP, so no reachable authentication exchange approaches 255 or wraps; the separate initial/reply sequence tests remain applicable
RFC8907-5.4-1 When the REPLY status equals TAC_PLUS_AUTHEN_STATUS_GETDATA, TAC_PLUS_AUTHEN_STATUS_GETUSER, or TAC_PLUS_AUTHEN_STATUS_GETPASS, authentication continues and the server SHOULD provide server_msg content for the client to prompt the user for more information. The client MUST then return a CONTINUE packet containing the requested information in the user_msg field. (§5.4, Description of Authentication Process) no test no test carries this requirement id; annotated {feature-declined}: "The entire exchange MUST consist of a single START packet and a single REPLY."; the PAP-specific rule is §5.4.2.2, which also restricts the reply to PASS, FAIL or ERROR. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding ASCII interactive workflows. internal/component/tacacs/client.go::Authenticate produces PAP through NewPAPAuthenStart, and validateReplyStatus rejects GETDATA/GETUSER/GETPASS rather than entering an interactive exchange; this is a selected method boundary, not a server-only obligation
RFC8907-5.4-2 If the information being requested by the server from the client is sensitive, then the server should set the TAC_PLUS_REPLY_FLAG_NOECHO flag. When the client queries the user for the information, the response MUST NOT be reflected in the user interface as it is entered. (§5.4, Description of Authentication Process) no test no test carries this requirement id; annotated {feature-declined}: "When the client queries the user for the information, the response MUST NOT be reflected in the user interface as it is entered."; this rule is conditional on interactive prompting. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding ASCII interaction. internal/component/tacacs/client.go::Authenticate receives an already supplied username/password through aaa.AuthRequest and never prompts in response to a TACACS+ reply
RFC8907-5.4.2.3-1 The entire exchange MUST consist of a single START packet and a single REPLY. The START packet MUST contain the username in the user field, and the data field is a concatenation of the PPP id, the challenge, and the response. (§5.4.2.3, CHAP Login) no test no test carries this requirement id; annotated {feature-declined}: "The START packet MUST contain the username in the user field, and the data field is a concatenation of the PPP id, the challenge, and the response."; §5.4.2.3 scopes this construction to authen_type TAC_PLUS_AUTHEN_TYPE_CHAP. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding CHAP. internal/component/tacacs/client.go::Authenticate accepts username/password and uses NewPAPAuthenStart; no product CHAP challenge/response workflow exists
RFC8907-5.4.2.4-1 The entire exchange MUST consist of a single START packet and a single REPLY. The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response. (§5.4.2.4, MS-CHAP v1 Login) no test no test carries this requirement id; annotated {feature-declined}: "The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response."; §5.4.2.4 scopes this construction to authen_type TAC_PLUS_AUTHEN_TYPE_MSCHAP. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding MS-CHAP v1. internal/component/tacacs/client.go::Authenticate accepts username/password and uses NewPAPAuthenStart; no product MS-CHAP v1 challenge/response workflow exists
RFC8907-5.4.2.5-1 The entire exchange MUST consist of a single START packet and a single REPLY. The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response. (§5.4.2.5, MS-CHAP v2 Login) no test no test carries this requirement id; annotated {feature-declined}: "The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response."; §5.4.2.5 scopes this construction to authen_type TAC_PLUS_AUTHEN_TYPE_MSCHAPV2. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding MS-CHAP v2. internal/component/tacacs/client.go::Authenticate accepts username/password and uses NewPAPAuthenStart; no product MS-CHAP v2 challenge/response workflow exists
RFC8907-5.4.2.6-1 In order to readily distinguish "ENABLE" requests from other types of request, the value of the authen_service field MUST be set to TAC_PLUS_AUTHEN_SVC_ENABLE when requesting an ENABLE. (§5.4.2.6, Enable Requests) no test no test carries this requirement id; annotated {feature-declined}: "The exchange MAY consist of multiple messages while the server collects the information it requires in order to allow changing the principal's privilege level."; §5.4.2.6 defines an ENABLE privilege-change workflow, and the service rule applies when requesting an ENABLE. On 2026-09-21 the owner selected `tacacs_methods='Keep PAP authentication'`, excluding ENABLE workflows. internal/component/tacacs/authen.go::NewPAPAuthenStart sets the LOGIN service for the management password callback; it does not request a privilege change. The separate prohibition on using ENABLE for other operations remains tested
RFC8907-10.5-1 New implementations, and upgrades of current implementations, MUST implement these recommendations. (§10.5, TACACS+ Best Practices) no test no test carries this requirement id; annotated {rollup}: RFC8907-10.5.1-1, RFC8907-10.5.1-2, RFC8907-10.5.2-1, RFC8907-10.5.4-1; Section 10.5 makes "these recommendations" of Sections 10.5.1 to 10.5.4 mandatory for new implementations, and those four rows carry the client-side recommendations the checklist gates; the MUSTs of Sections 10.5.3 and 10.5.5 bind TACACS+ servers, a role ze does not fill
RFC8907-4.6-2 A request MUST be dropped if TAC_PLUS_UNENCRYPTED_FLAG is set to true. (§4.5, Data Obfuscation; stable historical ID) no test no test carries this requirement id; annotated {not-applicable}: this request-receiver obligation binds a TACACS+ server. Ze implements the management AAA client, not a TACACS+ server; the client's separate obfuscation and reply-validation obligations remain applicable

Proof state

A tagged unit reads unproven where no discrimination record exists for it: nothing in this tree has been observed to break it, so the claim its tag makes is unproven.

RFC8907-4-1

This is the major TACACS+ version number. TAC_PLUS_MAJOR_VER := 0xc (§4.1)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. Positive TestRFC8907EveryRequestCarriesMajorVersion12 reads the captured request header (not an echo) and requires major nibble 0xc for authentication, authorization and accounting, so a client emitting 0xd goes red. Negative TestRFC8907ReplyWithOtherMajorVersionRefused mutates only the reply major nibble (header check runs before the body is read) for all 15 other values x 3 kinds and requires error + zero status; producer validateResponseHeader.

PolarityTestKind and tierProof state
negative TestTacacsClientRejectsBadResponseHeader unit/verify revert, verified
negative TestRFC8907ReplyWithOtherMajorVersionRefused unit/verify revert, verified
positive TestTacacsClientAuthenticatePass unit/verify revert, verified
positive TestRFC8907EveryRequestCarriesMajorVersion12 unit/verify revert, verified

RFC8907-4-2

TACACS+ clients only send packets containing odd sequence numbers, and TACACS+ servers only send packets containing even sequence numbers. (§4.1)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. Positive TestRFC8907ClientSendsOddSequenceNumbers reads the captured request seq_no and requires it odd for all 3 kinds, closing the old echo-server hole (a client sending 2 now goes red). Negative TestRFC8907ReplyWithOddSequenceNumberRefused sends each of the 128 odd server seq_no values x 3 kinds and requires refusal; only the reply seq_no differs.

PolarityTestKind and tierProof state
negative TestTacacsClientRejectsBadResponseHeader unit/verify revert, verified
negative TestRFC8907ReplyWithOddSequenceNumberRefused unit/verify revert, verified
positive TestTacacsClientAuthenticatePass unit/verify revert, verified
positive TestRFC8907ClientSendsOddSequenceNumbers unit/verify revert, verified

RFC8907-4-3

This number MUST be generated by a cryptographically strong random number generation method. (§4, Session Lifecycle)

Audit verdict: enforced (the tests do what the requirement demands), fresh. TestRFC8907SessionIDComesFromCryptoRand substitutes crypto/rand.Reader and requires the id to be exactly those octets; TestRandomSessionIDDistinct adds cross-session distinctness

PolarityTestKind and tierProof state
positive TestRandomSessionIDDistinct unit/verify unproven
positive TestRFC8907SessionIDComesFromCryptoRand unit/verify unproven

RFC8907-4-4

The Id for this TACACS+ session. This field does not change for the duration of the TACACS+ session. (§4.1)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29 after the invalid {single-polarity} marker was removed (correction recorded). Negative TestRFC8907ReplyChangingSessionIDRefused flips bit 0, bit 31 and all bits of the reply session_id (only field changed; type/version/seq/flags intact so the trySend session_id guard is the refusing check) for 3 kinds and requires error + zero status. Positive TestRFC8907ReplyKeepingSessionIDAccepted is the accepting path for all 3 kinds.

PolarityTestKind and tierProof state
negative TestRFC8907ReplyChangingSessionIDRefused unit/verify revert, verified
positive TestTacacsClientAuthenticatePass unit/verify revert, verified
positive TestRFC8907ReplyKeepingSessionIDAccepted unit/verify revert, verified

RFC8907-4-5

All length values are unsigned and in network byte order. (§4.1)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Re-judged 2026-10-12 (independent auditor). SHIFTED by 6e063fb498 (tests: give ten assert-nothing tests a real assertion), whose hunks sit in untagged sibling tests and the import block. The tagged unit is byte-identical (gate-verified) and no helper it calls changed. Verdict stands. Rejudged 2026-09-29. TestRFC8907LengthsAreUnsignedNetworkOrder asserts fixed wire octets for session_id and length (an independent big-endian oracle: a little-endian codec goes red), reads length 0xFFFFFFFE as unsigned, and reads 2-octet reply lengths 0x0100 and 0x8001 big-endian and unsigned in authentication, authorization and accounting replies (request lengths are 1 octet). {single-polarity: positive} holds: byte order has no refusal path. The marker's prose still describes the old symmetric round trip and should be refreshed; the argument itself stands.

PolarityTestKind and tierProof state
positive TestRFC8907LengthsAreUnsignedNetworkOrder unit/verify revert, verified
positive TestPacketHeaderMarshalRoundTrip unit/verify revert, verified

RFC8907-4.6-1

After a packet body is de-obfuscated, the lengths of the component values in the packet are summed. If the sum is not identical to the cleartext datalength value from the header, the packet MUST be discarded and an ERROR signaled. (§4.5, Data Obfuscation)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. The missing direction is now proven: TestRFC8907OverlongReplyComponentsRejected sends replies whose server_msg_len, data_len or argument length sums past the datalength, for all three kinds, and requires error + zero status (discard and ERROR). The < direction (TestRFC8907TrailingReplyBytesRejected) and exact positive (TestRFC8907ExactReplyLengthsAccepted) stand; producer validateReplyBody.

PolarityTestKind and tierProof state
negative TestRFC8907OverlongReplyComponentsRejected unit/verify revert, verified
negative TestRFC8907TrailingReplyBytesRejected unit/verify revert, verified
positive TestRFC8907ExactReplyLengthsAccepted unit/verify revert, verified

RFC8907-5-1

The sequence number must never wrap, i.e., if the sequence number 2^(8)-1 is ever reached, that session must terminate and be restarted with a sequence number of 1. (§4.1, Packet Header; maximum 255, not 254)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC8907-5-1, so no unit is bound to it.

RFC8907-7-1

This holds bitmapped flags. Valid values are: TAC_PLUS_ACCT_FLAG_START := 0x02 TAC_PLUS_ACCT_FLAG_STOP := 0x04 TAC_PLUS_ACCT_FLAG_WATCHDOG := 0x08 (§7.1)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. Positive TestRFC8907AccountingValidFlagsWritten writes 0x02, 0x04, 0x08 and 0x0a unchanged. Negative TestRFC8907AccountingOtherFlagsRefused refuses all 252 other values (every undefined bit 0x01, 0x10-0x80 and invalid combinations) and SendAccounting refuses 0x82 before contacting the server. Producer acct.go MarshalBinaryInto allowlist switch; a denylist now goes red.

PolarityTestKind and tierProof state
negative TestRFC8907AccountingOtherFlagsRefused unit/verify revert, verified
negative TestRFC8907AccountingMoreFlagRefused unit/verify revert, verified
positive TestAcctRequestMarshalStartStop unit/verify revert, verified
positive TestRFC8907AccountingValidFlagsWritten unit/verify revert, verified

RFC8907-7-2

The START and STOP flags are mutually exclusive. (§7.2)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: a request carrying START and STOP together. (b) TestRFC8907AccountingStartStopCombinationRefused requires errors.Is(err, errRequestInvalid) for Flags START|STOP; TestAcctRequestMarshalStartStop marshals START and STOP as separate flags.

PolarityTestKind and tierProof state
negative TestRFC8907AccountingStartStopCombinationRefused unit/verify unproven
positive TestAcctRequestMarshalStartStop unit/verify unproven

RFC8907-10-1

Clients MUST be implemented in a way that requires explicit configuration to enable the use of TAC_PLUS_UNENCRYPTED_FLAG. (§10.5.2)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Re-judged 2026-10-12 (independent auditor). SHIFTED by 6e063fb498 (tests: give ten assert-nothing tests a real assertion), whose hunks sit in untagged sibling tests and the import block. The tagged unit is byte-identical (gate-verified) and no helper it calls changed. Verdict stands. {single-polarity} on the row: no configuration enables the flag. (a) forbidden: any configuration state, including a keyless server, under which the client sends with TAC_PLUS_UNENCRYPTED_FLAG. (b) TestRFC8907UnencryptedModeIsNotReachableFromConfiguration reads the socket: a keyed config puts wire[3]&0x01 == 0 (assert.Zero), a keyless config writes no bytes (assert.Empty); TestRFC8907ClientNeverSendsUnobfuscatedBody requires the wire body to be the pseudo-pad XOR of the plaintext.

PolarityTestKind and tierProof state
positive TestRFC8907ClientNeverSendsUnobfuscatedBody unit/verify unproven
positive TestPacketMarshalRoundTrip unit/verify unproven
positive TestRFC8907UnencryptedModeIsNotReachableFromConfiguration unit/verify revert, verified

RFC8907-10-2

TACACS+ clients MUST NOT set TAC_PLUS_UNENCRYPTED_FLAG. (§10, Security)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Re-judged 2026-10-12 (independent auditor). SHIFTED by 6e063fb498 (tests: give ten assert-nothing tests a real assertion), whose hunks sit in untagged sibling tests and the import block. The tagged unit is byte-identical (gate-verified) and no helper it calls changed. Verdict stands. (a) forbidden: a client request whose flags octet has 0x01 set, or a send with no key. (b) TestRFC8907ClientNeverSendsUnobfuscatedBody fails when wire[3]&FlagUnencrypted != 0 and requires the body to decode through the pad; TestPacketMarshalNoEncryption requires ErrNoSharedSecret for nil and empty keys with zero bytes written; TestRFC8907BuildRejectsMissingSecret requires Build to refuse a keyless server with ErrNoSharedSecret and no authenticator.

PolarityTestKind and tierProof state
negative TestPacketMarshalNoEncryption unit/verify unproven
negative TestRFC8907BuildRejectsMissingSecret unit/verify unproven
positive TestRFC8907ClientNeverSendsUnobfuscatedBody unit/verify revert, verified

RFC8907-10.5.2-1

When a TACACS+ client receives responses from servers where: * the response packet was received from the server configured with a shared key, but the packet has TAC_PLUS_UNENCRYPTED_FLAG set, and * the response packet was received from the server configured not to use obfuscation, but the packet has TAC_PLUS_UNENCRYPTED_FLAG not set, the TACACS+ client MUST close the TCP session, and process the response in the same way that a TAC_PLUS_AUTHEN_STATUS_FAIL (authentication sessions) or TAC_PLUS_AUTHOR_STATUS_FAIL (authorization sessions) was received. (§10.5.2, Connections and Obfuscation)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. Clause (a), keyed server + TAC_PLUS_UNENCRYPTED_FLAG: TestRFC8907ObfuscationMismatchClosesAndFails asserts AUTHEN FAIL and AUTHOR FAIL (the two session kinds the RFC names) AND that the client closed the TCP (probe reads EOF/ECONNRESET after writing a single-connect reply); producer trySend closeAndEvict + sendToServers errObfuscationMismatch->FAIL. Positive TestRFC8907MatchingObfuscationKeepsStatusAndConnection keeps PASS/PASS_ADD and the TCP open, so a client closing on every reply goes red. Clause (b), keyless server + flag clear, cannot arise: Packet.MarshalInto refuses an empty key, so the keyless probe sees no request (asserted); the trySend guard still covers both directions. Old units in rfc8907_obfuscation_test.go remain valid.

PolarityTestKind and tierProof state
negative TestRFC8907ObfuscationMismatchClosesAndFails unit/verify revert, verified
negative TestRFC8907ClientRefusesUnobfuscatedReply unit/verify revert, verified
positive TestRFC8907MatchingObfuscationKeepsStatusAndConnection unit/verify revert, verified
positive TestRFC8907ClientAcceptsObfuscatedReply unit/verify revert, verified

RFC8907-6-1

Mandatory arguments require that the receiving side can handle the argument, that is, its implementation and configuration includes the details of how to act on it. If the client receives a mandatory argument that it cannot handle, it MUST consider the authorization to have failed. (§6.1)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: authorizing when a mandatory argument cannot be handled. (b) TestRFC8907MandatoryCommandPolicyDenied fails if an unsupported mandatory argument or value grants the command or consults the local fallback; TestRFC8907MandatorySessionPolicyDenied fails if session login grants profiles under an unenforceable mandatory argument; positives TestRFC8907MandatoryCommandPolicyAccepted (recognized mandatory values authorize) and TestRFC8907OptionalCommandPolicyIgnored (unsupported optional is disregarded).

PolarityTestKind and tierProof state
negative TestRFC8907MandatoryCommandPolicyDenied unit/verify unproven
negative TestRFC8907MandatorySessionPolicyDenied unit/verify unproven
positive TestRFC8907MandatoryCommandPolicyAccepted unit/verify unproven
positive TestRFC8907OptionalCommandPolicyIgnored unit/verify unproven

RFC8907-3.7-1

Usernames MUST be encoded and handled using the UsernameCasePreserved Profile specified in [RFC8265]. (§3.7, Treatment of Text Strings)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: a username sent without UsernameCasePreserved enforcement: no width mapping, no NFC, case folded, or a PRECIS-disallowed string (control, private use, ZWJ outside context, invalid UTF-8, bidi-rule violation) sent. (b) TestRFC8907UsernameProfileOnWire reads the username off the wire for all three services and requires "Alice\u0301" to arrive as "Alicé" (width-mapped, NFC, case kept); TestRFC8907ForbiddenUsernameNeverSent requires errRequestInvalid and no server contact for "alice\x00", "alice\ue000", "a\u200db", "\xff" and "\u05d0a" on every service.

PolarityTestKind and tierProof state
negative TestRFC8907ForbiddenUsernameNeverSent unit/verify unproven
positive TestRFC8907UsernameProfileOnWire unit/verify unproven

RFC8907-3.7-2

All other text fields in TACACS+ MUST be treated as printable byte arrays of US-ASCII as defined by [RFC0020]. The term "printable" used here means the fields MUST exclude the "Control Characters" defined in Section 5.2 of [RFC0020]. (§3.7, Treatment of Text Strings)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. With the old units, every text field Ze writes or reads is now refused on NUL, 0x1f, DEL and a non-ASCII byte: authentication port/rem_addr, authorization port/rem_addr/argument, accounting port/rem_addr/argument, authentication reply server_msg, authorization reply server_msg/data/argument, accounting reply server_msg/data (RFC 6.2/7.2 route those data fields to Section 3.7). Negative request cases leave every other field empty/valid, so validateText is the refusing check. Authentication reply data and START/CONTINUE data are correctly excluded (not a printable text encoding). Positive TestRFC8907PrintableTextInEveryField carries all 95 printable characters through each field. Rejudged 2026-10-10 after the validated-construction spec (9cbd3485ca, eaff5d644b, 7c25971594): the changed units only retype the registered handler from []string to command.ValidatedArgs (args read back through Tokens(), a clone of the dispatched tokens) and rename a local const command to commandName; every assertion, input and expected accounting/wire value is byte-identical, so the judgement above stands.

PolarityTestKind and tierProof state
negative TestRFC8907ControlCharactersRefusedInEveryField unit/verify revert, verified
negative TestRFC8907NonPrintableTextRejected unit/verify revert, verified
positive TestRFC8907PrintableTextInEveryField unit/verify revert, verified
positive TestRFC8907TrustedDispatchIdentitiesReachWire unit/verify revert, verified
positive TestRFC8907PrintableTextRoundTrip unit/verify revert, verified

RFC8907-4.1-1

To signal that any variable-length data fields are unused, the corresponding length values are set to zero. Such fields MUST be ignored, and treated as if not present. (§4.1, The TACACS+ Packet Header)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. New units extend the old data-only proof to server_msg, data and reply arguments in all three reply kinds: TestRFC8907ZeroLengthFieldsAreNotPresent requires empty msg/data and that zero-length arguments yield no entry (Args == [a=b]); TestRFC8907PresentFieldsFollowZeroLengthOnes requires present fields read at the offsets the zero-length fields leave (read-past goes red). Request-side fields are written by Ze, not read.

PolarityTestKind and tierProof state
negative TestRFC8907ZeroLengthFieldsAreNotPresent unit/verify revert, verified
negative TestRFC8907PresentZeroByteIsNotReadAsAbsent unit/verify revert, verified
positive TestRFC8907PresentFieldsFollowZeroLengthOnes unit/verify revert, verified
positive TestRFC8907ZeroLengthDataIsReadAsAbsent unit/verify revert, verified

RFC8907-4.1-2

The first packet in a session MUST have the sequence number 1, and each subsequent packet will increment the sequence number by one. (§4.1, The TACACS+ Packet Header)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: a session's first packet with a seq_no other than 1, or accepting a reply that does not follow it. (b) TestRFC8907FirstPacketCarriesSequenceOne requires requests[0].SeqNo == 1 on each new connection; TestRFC8907ReplyReusingSequenceOneIsRefused requires a reply carrying seq_no 1 to fail Authenticate and validateResponseHeader to report "sequence mismatch". The increment clause is descriptive ("will").

PolarityTestKind and tierProof state
negative TestRFC8907ReplyReusingSequenceOneIsRefused unit/verify revert, verified
positive TestRFC8907FirstPacketCarriesSequenceOne unit/verify revert, verified

RFC8907-4.1-3

All other bits MUST be ignored when reading, and SHOULD be set to zero when writing. (§4.1, The TACACS+ Packet Header)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: refusing a reply because undefined flag bits are set, or letting undefined bits mask a defined flag. (b) TestRFC8907UnknownHeaderFlagsIgnored sets reply flags 0xf2 (undefined bits only) and fails unless status == PASS with no error; TestRFC8907UnknownFlagsDoNotMaskDowngrade sets 0x81 and fails unless the result is FAIL. The SHOULD-zero-on-write half is not a MUST.

PolarityTestKind and tierProof state
negative TestRFC8907UnknownFlagsDoNotMaskDowngrade unit/verify unproven
positive TestRFC8907UnknownHeaderFlagsIgnored unit/verify unproven

RFC8907-4.3-1

The client MUST NOT send a second packet on a connection until single-connect status has been established. (§4.3, Single Connection Mode)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: a second packet on a connection before the server echoed single-connect. (b) TestRFC8907NoSecondPacketWithoutSingleConnect (no echo) requires two connections and requestsOn(0) of length 1; TestRFC8907SecondSessionReusesEstablishedConnection (echo) requires one connection carrying two requests.

PolarityTestKind and tierProof state
negative TestRFC8907NoSecondPacketWithoutSingleConnect unit/verify revert, verified
positive TestRFC8907SecondSessionReusesEstablishedConnection unit/verify revert, verified

RFC8907-4.3-2

No provision is made for changing Single Connection Mode after the first two packets; the client and server MUST ignore the flag after the second packet on a connection. (§4.3, Single Connection Mode)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: acting on the single-connect flag after the second packet, by leaving the pool when a later reply clears it or by re-signalling it. (b) TestRFC8907FlagClearedOnLaterReplyIsIgnored requires one connection carrying three requests although replies after the first clear the flag; TestRFC8907ClientDoesNotResignalSingleConnect requires requests[1].Flags and requests[2].Flags == 0.

PolarityTestKind and tierProof state
negative TestRFC8907ClientDoesNotResignalSingleConnect unit/verify revert, verified
positive TestRFC8907FlagClearedOnLaterReplyIsIgnored unit/verify revert, verified

RFC8907-4.3-3

The client MUST accommodate such closures on a TCP session even after Single Connection Mode has been established. (§4.3, Single Connection Mode)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Independent rejudgment 2026-10-11 (judge did not author a832af8548 or the tests); replaces the author's pending-confirmation note. RFC 8907 Section 4.3: "The client MUST accommodate such closures on a TCP session even after Single Connection Mode has been established." The closures meant are the server's, e.g. the inactivity timeout of the preceding sentence. Positive TestRFC8907ServerClosureOfPooledConnectionIsAccommodated: newSessionServer echo=true answers the first request with TAC_PLUS_SINGLE_CONNECT_FLAG, so Single Connection Mode is established in the first two packets; closeAfter=1 then closes the idle TCP and waitClosed confirms it before session 2, which must PASS on a second connection carrying exactly one request. Negative TestRFC8907ClosureMidSessionOnPooledConnectionIsAccommodated: midExchangeCloser echoes the flag, counts [2] prove two sessions shared the established TCP, then the server reads session 3's request and closes unanswered; session 3 must still PASS and counts must be [3,1]. Producer: client.go sendReceive retries once on pooledConnErr with a fresh dial after trySend's closeAndEvict; trySend returns pooledConnErr only for a reused (established) connection, so the fresh-dial closure correctly surfaces as an error. Removing that retry fails both: session 2/3 would read EOF on the evicted TCP and authenticatePass would see an error. Both units sit on an established single-connect TCP, isolate the closure, and assert the exact outcome (PASS plus the connection and request counts). Limit kept on record: the two discrimination records are revert halts of sendReceive, not a break of the retry alone, so question 2 is answered here by reading, not by a recorded break. Verdict enforced confirmed.

PolarityTestKind and tierProof state
negative TestRFC8907ClosureMidSessionOnPooledConnectionIsAccommodated unit/verify revert, verified
positive TestRFC8907ServerClosureOfPooledConnectionIsAccommodated unit/verify revert, verified

RFC8907-4.4-1

The server responds with an ERROR to indicate that the processing of the request did not complete. The client cannot apply the result, and it MUST behave as if the server could not be connected to. (§4.4, Session Completion)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: applying an ERROR reply as a result (terminal rejection) instead of behaving as if the server were unreachable. (b) TestRFC8907ErrorUsesBackupServer fails for authentication, authorization and accounting unless the backup is contacted and its status 1 is returned with no error; TestRFC8907FailDoesNotUseBackupServer is the discriminating pair: a FAIL keeps failStatus and never contacts the backup.

PolarityTestKind and tierProof state
negative TestRFC8907FailDoesNotUseBackupServer unit/verify unproven
positive TestRFC8907ErrorUsesBackupServer unit/verify unproven

RFC8907-4.4-2

If Single Connection Mode was enabled, but an ERROR occurred due to connection issues (such as an incorrect secret (see Section 4.5)), then any further new sessions MUST NOT be accepted on the connection. (§4.4, Session Completion)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: a new session on a single-connect connection after a reply on it failed validation. (b) TestRFC8907NoNewSessionOnBrokenPooledConnection (session_id corrupted on the second reply) requires two connections and requestsOn(0) of length 2, so a third request on the broken TCP goes red; TestRFC8907HealthyPooledConnectionKeepsAcceptingSessions requires one connection carrying three requests.

PolarityTestKind and tierProof state
negative TestRFC8907HealthyPooledConnectionKeepsAcceptingSessions unit/verify revert, verified
positive TestRFC8907NoNewSessionOnBrokenPooledConnection unit/verify revert, verified

RFC8907-4.4-3

Once all active sessions are completed, then the connection MUST be closed. (§4.4, Session Completion)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: leaving the broken single-connect connection open. (b) TestRFC8907BrokenPooledConnectionIsClosed requires waitClosed on the server side of the broken TCP; TestRFC8907HealthyPooledConnectionStaysOpen requires isClosed false after three healthy sessions.

PolarityTestKind and tierProof state
negative TestRFC8907HealthyPooledConnectionStaysOpen unit/verify revert, verified
positive TestRFC8907BrokenPooledConnectionIsClosed unit/verify revert, verified

RFC8907-5.1-1

The username is optional in this packet, depending upon the class of authentication. If it is absent, the client MUST set user_len to 0. (§5.1, The Authentication START Packet Body)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: a START with no username whose user_len is not 0. (b) TestRFC8907AuthenStartAbsentUserWritesZeroLength requires body[4] == 0, no user bytes and the port at offset 8; TestRFC8907AuthenStartPresentUserWritesItsLength requires body[4] == len("alice") and the user bytes.

PolarityTestKind and tierProof state
negative TestRFC8907AuthenStartPresentUserWritesItsLength unit/verify revert, verified
positive TestRFC8907AuthenStartAbsentUserWritesZeroLength unit/verify revert, verified

RFC8907-5.4-1

When the REPLY status equals TAC_PLUS_AUTHEN_STATUS_GETDATA, TAC_PLUS_AUTHEN_STATUS_GETUSER, or TAC_PLUS_AUTHEN_STATUS_GETPASS, authentication continues and the server SHOULD provide server_msg content for the client to prompt the user for more information. The client MUST then return a CONTINUE packet containing the requested information in the user_msg field. (§5.4, Description of Authentication Process)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC8907-5.4-1, so no unit is bound to it.

RFC8907-5.4-2

If the information being requested by the server from the client is sensitive, then the server should set the TAC_PLUS_REPLY_FLAG_NOECHO flag. When the client queries the user for the information, the response MUST NOT be reflected in the user interface as it is entered. (§5.4, Description of Authentication Process)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC8907-5.4-2, so no unit is bound to it.

RFC8907-5.4.2.2-1

The entire exchange MUST consist of a single START packet and a single REPLY. (§5.4.2.2, PAP Login)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: a PAP login with more than one START/REPLY, including a CONTINUE. (b) TestRFC8907PAPExchangeIsOneStartOneReply requires exactly one authentication request on the connection; TestRFC8907PAPClientSendsNoContinue replies GETPASS and requires an error, a nil reply and requestsOn(0) of length 1.

PolarityTestKind and tierProof state
negative TestRFC8907PAPClientSendsNoContinue unit/verify revert, verified
positive TestRFC8907PAPExchangeIsOneStartOneReply unit/verify revert, verified

RFC8907-5.4.2.2-2

The START packet MUST contain a username and the data field MUST contain the PAP ASCII password. (§5.4.2.2, PAP Login)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. Positive TestRFC8907PAPStartOnWireCarriesUserAndPassword decodes the START from the wire and requires user=alice and data=the password. Negative TestRFC8907PAPStartWithoutUsernameNeverSent requires errRequestInvalid and that the server is never contacted, the tagged red assertion for 'MUST contain a username' the old verdict lacked.

PolarityTestKind and tierProof state
negative TestRFC8907PAPStartWithoutUsernameNeverSent unit/verify revert, verified
negative TestRFC8907PAPStartRefusesPasswordItCannotCarry unit/verify revert, verified
positive TestRFC8907PAPStartOnWireCarriesUserAndPassword unit/verify revert, verified
positive TestRFC8907PAPStartCarriesUserAndPassword unit/verify revert, verified

RFC8907-5.4.2.3-1

The entire exchange MUST consist of a single START packet and a single REPLY. The START packet MUST contain the username in the user field, and the data field is a concatenation of the PPP id, the challenge, and the response. (§5.4.2.3, CHAP Login)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC8907-5.4.2.3-1, so no unit is bound to it.

RFC8907-5.4.2.4-1

The entire exchange MUST consist of a single START packet and a single REPLY. The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response. (§5.4.2.4, MS-CHAP v1 Login)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC8907-5.4.2.4-1, so no unit is bound to it.

RFC8907-5.4.2.5-1

The entire exchange MUST consist of a single START packet and a single REPLY. The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response. (§5.4.2.5, MS-CHAP v2 Login)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC8907-5.4.2.5-1, so no unit is bound to it.

RFC8907-5.4.2.6-1

In order to readily distinguish "ENABLE" requests from other types of request, the value of the authen_service field MUST be set to TAC_PLUS_AUTHEN_SVC_ENABLE when requesting an ENABLE. (§5.4.2.6, Enable Requests)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC8907-5.4.2.6-1, so no unit is bound to it.

RFC8907-5.4.2.6-2

It MUST NOT be set to this value when requesting any other operation. (§5.4.2.6, Enable Requests)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29 on the narrowed row (verbatim second sentence of 5.4.2.6; the first sentence is RFC8907-5.4.2.6-1, feature-declined; correction recorded). Negative TestRFC8907NoRequestCarriesEnableService checks the authen_service octet of all five requests Ze sends (PAP START and session/command authorization from the wire, accounting START/STOP) and requires none be 0x02; it is no longer the positive's assertion in a second hat. Positive TestRFC8907PAPLoginOnWireCarriesLoginService requires LOGIN on the wire START.

PolarityTestKind and tierProof state
negative TestRFC8907NoRequestCarriesEnableService unit/verify revert, verified
negative TestRFC8907LoginStartNeverCarriesEnableService unit/verify revert, verified
positive TestRFC8907PAPLoginOnWireCarriesLoginService unit/verify revert, verified
positive TestRFC8907LoginStartCarriesLoginService unit/verify revert, verified

RFC8907-5.4.3-1

If a client does not implement the TAC_PLUS_AUTHEN_STATUS_RESTART option, then it MUST process the response as if the status was TAC_PLUS_AUTHEN_STATUS_FAIL. (§5.4.3, Aborting an Authentication Session)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: processing RESTART as anything but FAIL. (b) TestRFC8907RestartIsProcessedAsFail requires ErrorIs aaa.ErrAuthRejected, Authenticated false and Source == backendName; TestRFC8907ErrorIsNotProcessedAsFail is the discriminating pair: ERROR must not be ErrAuthRejected.

PolarityTestKind and tierProof state
negative TestRFC8907ErrorIsNotProcessedAsFail unit/verify revert, verified
positive TestRFC8907RestartIsProcessedAsFail unit/verify revert, verified

RFC8907-6.1-1

The user_len MUST indicate the length of the user field, in bytes. (§6.1, The Authorization REQUEST Packet Body)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. Positive TestRFC8907AuthorUserLenCountsBytes: 'Alicé' writes user_len 6 (a rune count writes 5) and a 255-byte multibyte user writes 255, with the user bytes read back at that length. Negative TestRFC8907AuthorUserLenRefusesRuneCount: 128 runes / 256 bytes is refused, which a rune-count producer would accept.

PolarityTestKind and tierProof state
negative TestRFC8907AuthorUserLenRefusesRuneCount unit/verify revert, verified
negative TestRFC8907AuthorRequestRefusesUserItCannotMeasure unit/verify revert, verified
positive TestRFC8907AuthorUserLenCountsBytes unit/verify revert, verified
positive TestRFC8907AuthorRequestUserLenMatchesUser unit/verify revert, verified

RFC8907-6.1-2

An argument name MUST NOT contain either of the separators. (§6.1, The Authorization REQUEST Packet Body)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: an argument whose name contains = or *. (b) TestRFC8907ArgumentNamesCarryNoSeparator requires every built name to be service, cmd or cmd-arg; TestRFC8907ArgumentValueKeepsSeparatorOutOfName requires splitTacacsArgs("set key=a*b value=*") to equal exactly service=shell, cmd=set, cmd-arg=key=a*b, cmd-arg=value=*, so a token carried as a name goes red.

PolarityTestKind and tierProof state
negative TestRFC8907ArgumentValueKeepsSeparatorOutOfName unit/verify revert, verified
positive TestRFC8907ArgumentNamesCarryNoSeparator unit/verify revert, verified

RFC8907-6.2-1

If the status equals TAC_PLUS_AUTHOR_STATUS_PASS_ADD, then the arguments specified in the request are authorized and the arguments in the response MUST be applied according to the rules described above. (§6.2, The Authorization REPLY Packet Body)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: under PASS_ADD, dropping the requested arguments or not applying the returned ones. (b) TestRFC8907PassAddRetainsCommand fails if the requested command is lost; TestRFC8907PassAddCannotIgnoreCommandExtension fails if an added mandatory cmd-arg is ignored or falls back to local policy; TestRFC8907SessionPrivilegeApplied fails unless the returned priv-lvl selects its mapped profile.

PolarityTestKind and tierProof state
negative TestRFC8907PassAddCannotIgnoreCommandExtension unit/verify unproven
positive TestRFC8907PassAddRetainsCommand unit/verify unproven
positive TestRFC8907SessionPrivilegeApplied unit/verify unproven

RFC8907-6.2-2

If the status equals TAC_PLUS_AUTHOR_STATUS_PASS_REPL, then the client MUST use the authorization argument-value pairs (if any) in the response instead of the authorization argument- value pairs from the request. (§6.2, The Authorization REPLY Packet Body)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: under PASS_REPL, using the request arguments instead of the reply ones. (b) TestRFC8907PassReplCannotAuthorizeOriginalCommand fails if an empty, incomplete, changed, reordered or re-split replacement authorizes the original command or consults the local fallback; TestRFC8907IncompleteSessionReplacementDenied fails if session replacement inherits service/cmd from the request; positives TestRFC8907PassReplPreservesExactCommand and TestRFC8907SessionReplacementMapsZero (reply priv-lvl 0 applied).

PolarityTestKind and tierProof state
negative TestRFC8907IncompleteSessionReplacementDenied unit/verify unproven
negative TestRFC8907PassReplCannotAuthorizeOriginalCommand unit/verify unproven
positive TestRFC8907PassReplPreservesExactCommand unit/verify unproven
positive TestRFC8907SessionReplacementMapsZero unit/verify unproven

RFC8907-6.2-3

If the status equals TAC_PLUS_AUTHOR_STATUS_FAIL, then the requested authorization MUST be denied. (§6.2, The Authorization REPLY Packet Body)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: allowing a request the server answered with FAIL. (b) TestRFC8907AuthorizationFailDenies requires Authorize false and zero calls to a permissive local policy; TestRFC8907AuthorizationPassAddIsNotDenied requires PASS_ADD to allow.

PolarityTestKind and tierProof state
negative TestRFC8907AuthorizationPassAddIsNotDenied unit/verify revert, verified
positive TestRFC8907AuthorizationFailDenies unit/verify revert, verified

RFC8907-7.2-1

The STOP flag MUST NOT be set in conjunction with the WATCHDOG flag. (§7.2, The Accounting REPLY Packet Body)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: STOP with WATCHDOG set. (b) TestRFC8907AccountingStopWatchdogCombinationRefused requires errRequestInvalid for STOP|WATCHDOG; TestRFC8907StopRecordNeverCarriesWatchdog requires Flags&WATCHDOG == 0 on the queued STOP; TestRFC8907StopRecordCarriesStopFlagOnly requires Flags == STOP.

PolarityTestKind and tierProof state
negative TestRFC8907StopRecordNeverCarriesWatchdog unit/verify revert, verified
negative TestRFC8907AccountingStopWatchdogCombinationRefused unit/verify unproven
positive TestRFC8907StopRecordCarriesStopFlagOnly unit/verify revert, verified

RFC8907-8-1

Clients MUST use these arguments when supporting the corresponding use cases. (§8, Argument-Value Pairs)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. Every request kind Ze sends is now asserted: authorization (command request exactly service/cmd/cmd-arg, session request service=shell cmd=) in TestRFC8907AuthorizationRequestsUseDictionaryArguments and TestRFC8907AuthorizationRequestsCarryNoForeignArgument, accounting in the old units. Exact equality catches a private name substituted for a dictionary one.

PolarityTestKind and tierProof state
negative TestRFC8907CommandRecordsCarryNoForeignArgument unit/verify revert, verified
negative TestRFC8907AuthorizationRequestsCarryNoForeignArgument unit/verify revert, verified
positive TestRFC8907CommandRecordsUseDictionaryArguments unit/verify revert, verified
positive TestRFC8907AuthorizationRequestsUseDictionaryArguments unit/verify revert, verified

RFC8907-8.1-1

TACACS+ implementations MUST verify that they can accommodate the lengths of numeric arguments before attempting to process them. If the length cannot be accommodated, then the argument MUST be regarded as not handled and the logic in "Authorization" (Section 6.1) regarding the processing of arguments MUST be applied. (§8.1)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: processing a numeric argument whose length Ze cannot accommodate, or not applying Section 6.1 to it. (b) TestRFC8907InvalidMandatoryPrivilegeDenied asserts ErrAuthRejected and zero profiles for priv-lvl=18446744073709551631 and a 242-digit value (mandatory -> authorization failed); TestRFC8907OverlongOptionalPrivilegeCannotElevate asserts the overlong optional priv-lvl is disregarded (profile ops); TestRFC8907SessionPrivilegeApplied is the positive (priv-lvl=15 -> admin). priv-lvl is the only numeric argument Ze processes; timeout and others are refused as unsupported mandatory.

PolarityTestKind and tierProof state
negative TestRFC8907InvalidMandatoryPrivilegeDenied unit/verify unproven
positive TestRFC8907OverlongOptionalPrivilegeCannotElevate unit/verify unproven
positive TestRFC8907SessionPrivilegeApplied unit/verify unproven

RFC8907-8.1-2

Absolute date/times are specified in seconds since the epoch, 12:00am, January 1, 1970. The time zone MUST be UTC unless a time zone argument is specified. (§8.1)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. stop_time, the missing absolute time, is now proven: TestRFC8907StopTimeIsEpochSeconds bounds it to [before, after] Unix seconds and TestRFC8907StopTimeIgnoresLocalZone sets time.Local +5h and requires no shift and no timezone argument. start_time stays proven by the old units.

PolarityTestKind and tierProof state
negative TestRFC8907StartTimeIgnoresLocalZone unit/verify revert, verified
negative TestRFC8907StopTimeIgnoresLocalZone unit/verify revert, verified
positive TestRFC8907StartTimeIsEpochSeconds unit/verify revert, verified
positive TestRFC8907StopTimeIsEpochSeconds unit/verify revert, verified

RFC8907-8.2-1

Specifying a service argument indicates that this is a request for authorization or accounting of that service. For example: "shell", "tty-server", "connection", "system" and "firewall"; others may be chosen for the required application. This argument MUST always be included. (§8.2)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. Service is now asserted on every request kind: command and session authorization (service=shell first) and accounting START/STOP (TestRFC8907EveryRequestKindLeadsWithService); TestRFC8907NoRequestKindOmitsService requires exactly one service in each, including the session request with empty cmd and records for an argless command.

PolarityTestKind and tierProof state
negative TestRFC8907NoRequestKindOmitsService unit/verify revert, verified
negative TestRFC8907ServiceArgumentPresentForEmptyCommand unit/verify revert, verified
positive TestRFC8907EveryRequestKindLeadsWithService unit/verify revert, verified
positive TestRFC8907ServiceArgumentAlwaysFirst unit/verify revert, verified

RFC8907-8.2-2

The "cmd" argument MUST be specified if service equals "shell". (§8.2, Authorization Arguments)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. Every service=shell request now carries cmd under a tagged unit: command request cmd=show, session request cmd=, accounting START/STOP cmd=show (TestRFC8907EveryShellRequestCarriesCmd); TestRFC8907ShellRequestNeverLacksCmd covers the edge inputs (empty session cmd, argless 'show' records); old units cover the empty command in splitTacacsArgs.

PolarityTestKind and tierProof state
negative TestRFC8907ShellRequestNeverLacksCmd unit/verify revert, verified
negative TestRFC8907CmdArgumentPresentForEmptyCommand unit/verify revert, verified
positive TestRFC8907EveryShellRequestCarriesCmd unit/verify revert, verified
positive TestRFC8907CmdArgumentFollowsShellService unit/verify revert, verified

RFC8907-8.3-1

The following arguments are defined for TACACS+ accounting only. They MUST precede any argument-value pairs that are defined in "Authorization" (Section 6). (§8.3)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: a Section 8.2 argument (service, cmd, cmd-arg) before task_id/start_time/stop_time in an accounting record. (b) TestRFC8907AccountingArgumentsPrecedeAuthorizationOnes asserts task_id and start_time (START) and task_id and stop_time (STOP) index below service; TestRFC8907NoAuthorizationArgumentPrecedesAccountingOne fails on any service/cmd/cmd-arg seen before task_id or start_time in START. Both records share accountingArguments.

PolarityTestKind and tierProof state
negative TestRFC8907NoAuthorizationArgumentPrecedesAccountingOne unit/verify revert, verified
positive TestRFC8907AccountingArgumentsPrecedeAuthorizationOnes unit/verify revert, verified

RFC8907-8.3-2

Start and stop records for the same event MUST have matching task_id argument values. (§8.3, Accounting Arguments)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: START and STOP of one command with different task_id values. (b) TestRFC8907StartAndStopShareTaskID require.Equal(startID, stopID); TestRFC8907SecondCommandCarriesOtherTaskID require.NotEqual for a second command.

PolarityTestKind and tierProof state
negative TestRFC8907SecondCommandCarriesOtherTaskID unit/verify revert, verified
positive TestRFC8907StartAndStopShareTaskID unit/verify revert, verified

RFC8907-8.3-3

The client MUST ensure that active task_ids are not duplicated; a client MUST NOT reuse a task_id in a start record until it has sent a stop record for that task_id. (§8.3, Accounting Arguments)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: two active START records sharing a task_id, or a task_id reused in START before its STOP. (b) TestRFC8907ActiveTaskIDsAreDistinct fails on any repeat among sixteen START records with no STOP; TestRFC8907TaskIDNeverReappears asserts a used task_id never reappears in eight later STARTs.

PolarityTestKind and tierProof state
negative TestRFC8907TaskIDNeverReappears unit/verify revert, verified
positive TestRFC8907ActiveTaskIDsAreDistinct unit/verify revert, verified

RFC8907-8.3-4

To support this mode of operation, TACACS+ client devices MUST be configured to send an accounting start packet for every command entered, irrespective of how the commands were authorized. (§8.3, Accounting Arguments)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: an entered command with no accounting START, including a command authorization denied or that is unknown or malformed. (b) TestDispatcherAccountsRefusedCommands asserts starts == [input] for a denied, an unknown and a malformed command; TestRFC8907TypedDispatchAccountsDeniedCommand asserts START and STOP for a denied typed dispatch; api_test.go denied-stream and TACACS wire tests (rfc8907_dispatch_wire_test.go) assert real START packets; TestRFC8907AccountingRequiresDestination refuses accounting with no destination at Build. Rejudged 2026-10-10 after the validated-construction spec (9cbd3485ca, eaff5d644b, 7c25971594): the changed units only retype the registered handler from []string to command.ValidatedArgs (args read back through Tokens(), a clone of the dispatched tokens) and rename a local const command to commandName; every assertion, input and expected accounting/wire value is byte-identical, so the judgement above stands.

PolarityTestKind and tierProof state
negative TestRFC8907BundleRetirementWaitsForAccountingPair unit/verify unproven
negative TestAPIStreamSourceAuthorizesReadOnly unit/verify unproven
negative TestDispatcherAccountsRefusedCommands unit/verify unproven
negative TestRFC8907AccountingStopDrainsAcceptedStarts unit/verify unproven
negative TestRFC8907OversizedCommandAccountingStillReachesWire unit/verify unproven
negative TestRFC8907AccountingRequiresDestination unit/verify unproven
positive TestInstallNoBGPAAADispatchPairsAccountingAcrossSwap unit/verify revert, verified
positive TestAPIStreamSourceRunsStreamingHandler unit/verify unproven
positive TestRFC8907PluginDispatchAccountsCommand unit/verify unproven
positive TestRFC8907TypedDispatchAccountsDeniedCommand unit/verify unproven
positive TestDispatcherAccountingWithoutUsername unit/verify unproven
positive TestRFC8907AccountingSaturationRetainsEveryStart unit/verify unproven
positive TestRFC8907TrustedDispatchIdentitiesReachWire unit/verify unproven

RFC8907-8.3-5

These "Command Accounting" packets MUST include the "service" and "cmd" arguments, and if needed, the "cmd-arg" arguments detailed in Section 8.2. (§8.3, Accounting Arguments)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: a command accounting record without service or cmd, or dropping needed cmd-arg arguments. (b) TestRFC8907CommandRecordsCarryServiceCmdAndArgs asserts service=shell, cmd=show, cmd-arg=bgp, cmd-arg=summary in START and STOP; TestRFC8907EmptyCommandRecordStillCarriesServiceAndCmd asserts service=shell and cmd= for an empty command.

PolarityTestKind and tierProof state
negative TestRFC8907EmptyCommandRecordStillCarriesServiceAndCmd unit/verify revert, verified
positive TestRFC8907CommandRecordsCarryServiceCmdAndArgs unit/verify revert, verified

RFC8907-10.5-1

New implementations, and upgrades of current implementations, MUST implement these recommendations. (§10.5, TACACS+ Best Practices)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC8907-10.5-1, so no unit is bound to it.

RFC8907-10.5.1-1

TACACS+ servers and clients MUST treat shared secrets as sensitive data to be managed securely, as would be expected for other sensitive data such as identity credential information. (§10.5.1, Shared Secrets)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: exposing the shared secret in display, diagnostics, logs or accounting records. (b) TestRFC8907SharedSecretConfigBuildAndDisplay asserts the display tree masks the key while the live key still decodes a real exchange; TestRFC8907SharedSecretDiagnosticRedaction fails on the key, its base64 or byte list in fmt, %#v, JSON and slog output; TestRFC8907SharedSecretCommandRedaction fails on secret words in DisplayCommand; TestRFC8907AccountingRedactsConfigSecretWithoutChangingExecution asserts accounting tokens carry the placeholder. Rejudged 2026-10-10 after the validated-construction spec (9cbd3485ca, eaff5d644b, 7c25971594): the changed units only retype the registered handler from []string to command.ValidatedArgs (args read back through Tokens(), a clone of the dispatched tokens) and rename a local const command to commandName; every assertion, input and expected accounting/wire value is byte-identical, so the judgement above stands.

PolarityTestKind and tierProof state
negative TestRFC8907AccountingRedactsConfigSecretWithoutChangingExecution unit/verify unproven
negative TestRFC8907SharedSecretCommandRedaction unit/verify unproven
negative TestRFC8907SharedSecretDiagnosticRedaction unit/verify unproven
positive TestRFC8907SharedSecretConfigBuildAndDisplay unit/verify unproven

RFC8907-10.5.1-2

* TACACS+ servers and clients MUST support shared keys that are at least 32 characters long. (§10.5.1, Shared Secrets)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: rejecting or truncating a shared key of 32 characters or more. (b) TestRFC8907LongSharedKeysAuthenticate completes a PASS exchange with 32- and 300-character keys; TestRFC8907SharedKeyIsNotTruncated asserts the pad for 32 characters differs from the pad for the first 31; TestRFC8907SharedSecretConfigBuildAndDisplay drives a 32-character key through Build into a real accounting exchange.

PolarityTestKind and tierProof state
negative TestRFC8907SharedKeyIsNotTruncated unit/verify revert, verified
positive TestRFC8907LongSharedKeysAuthenticate unit/verify revert, verified
positive TestRFC8907SharedSecretConfigBuildAndDisplay unit/verify unproven

RFC8907-10.5.4-1

The cost of the flexibility is that administrators and implementers MUST ensure that the argument and value pairs shared between the clients and servers have consistent interpretation. (§10.5.4, Authorization)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Rejudged 2026-09-29. The consistent interpretation of shared values Ze consumes is now proven: priv-lvl 0/1/15 select exactly their profiles, and 16, ' 15', '0x0f', '1.5' are rejected (ErrAuthRejected, no profile); full-width digits refused with no profile; a PASS_REPL naming the same cmd/cmd-arg in order authorizes, and a case or order change denies. Old units keep the unrecognized-mandatory-argument case.

PolarityTestKind and tierProof state
negative TestRFC8907SharedArgumentsNeverReinterpreted unit/verify revert, verified
negative TestRFC8907MandatoryCommandPolicyDenied unit/verify revert, verified
negative TestRFC8907MandatorySessionPolicyDenied unit/verify revert, verified
positive TestRFC8907SharedArgumentsKeepDefinedMeaning unit/verify revert, verified
positive TestRFC8907MandatoryCommandPolicyAccepted unit/verify revert, verified

RFC8907-4.6-2

A request MUST be dropped if TAC_PLUS_UNENCRYPTED_FLAG is set to true. (§4.5, Data Obfuscation; stable historical ID)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC8907-4.6-2, so no unit is bound to it.

RFC8907-x-2

This document deprecates the redirection mechanism using the TAC_PLUS_AUTHEN_STATUS_FOLLOW option, which was included in "The Draft". As part of this process, the secret key for a new server was sent to the client. This public exchange of secret keys means that once one session is broken, it may be possible to leverage that key to attacking connections to other servers. This mechanism MUST NOT be used in modern deployments. It MUST NOT be used outside a secured deployment. (§10.2)

Audit verdict: enforced (the tests do what the requirement demands), fresh. (a) forbidden: the client using the FOLLOW redirection, by contacting the named server or treating FOLLOW as success or fallback. (b) TestRFC8907FollowTargetIsNeverContacted fails if the FOLLOW target receives a connection; TestRFC8907FollowIsNotAuthenticated asserts ErrAuthRejected and not authenticated; TestRFC8907AuthorizationFollowDeniesWithoutFallback asserts denial with zero local fallback calls.

PolarityTestKind and tierProof state
negative TestRFC8907FollowTargetIsNeverContacted unit/verify revert, verified
positive TestRFC8907AuthorizationFollowDeniesWithoutFallback unit/verify unproven
positive TestRFC8907FollowIsNotAuthenticated unit/verify revert, verified

Extraction sign-off

FieldValue
Reviewer claude
Signed off 2026-09-21
Register rfc2119
Source rfc/full/rfc8907.txt
Source fingerprint 8bc695c4b9949009
Record rfc/extraction/rfc8907.json
Mapped sentences 50
Declined as scope 54
Relocated to a spec, which Ze OWES 0
Unclassified 0

Sections

SectionNameSitesDispositionReason
front not stated 0 walked not stated
1 not stated 0 walked not stated
2 not stated 0 walked not stated
3 not stated 0 walked not stated
3.1 not stated 0 walked not stated
3.2 not stated 0 walked not stated
3.3 not stated 0 walked not stated
3.4 not stated 0 walked not stated
3.5 not stated 0 walked not stated
3.6 not stated 1 walked not stated
3.7 not stated 3 walked not stated
4 not stated 0 walked not stated
4.1 not stated 6 walked not stated
4.2 not stated 0 walked not stated
4.3 not stated 4 walked not stated
4.4 not stated 3 walked not stated
4.5 not stated 7 walked not stated
5 not stated 0 walked not stated
5.1 not stated 1 walked not stated
5.2 not stated 0 walked not stated
5.3 not stated 0 walked not stated
5.4 not stated 2 walked not stated
5.4.1 not stated 0 walked not stated
5.4.2 not stated 1 walked not stated
5.4.2.1 not stated 3 walked not stated
5.4.2.2 not stated 3 walked not stated
5.4.2.3 not stated 3 walked not stated
5.4.2.4 not stated 4 walked not stated
5.4.2.5 not stated 4 walked not stated
5.4.2.6 not stated 2 walked not stated
5.4.2.7 not stated 2 walked not stated
5.4.3 not stated 1 walked not stated
6 not stated 0 walked not stated
6.1 not stated 4 walked not stated
6.2 not stated 4 walked not stated
7 not stated 0 walked not stated
7.1 not stated 0 walked not stated
7.2 not stated 5 walked not stated
8 not stated 1 walked not stated
8.1 not stated 3 walked not stated
8.2 not stated 2 walked not stated
8.3 not stated 6 walked not stated
9 not stated 0 walked not stated
10 not stated 0 walked not stated
10.1 not stated 1 walked not stated
10.2 not stated 2 walked not stated
10.3 not stated 0 walked not stated
10.4 not stated 0 walked not stated
10.5 not stated 3 walked not stated
10.5.1 not stated 7 walked not stated
10.5.2 not stated 10 walked not stated
10.5.3 not stated 2 walked not stated
10.5.4 not stated 2 walked not stated
10.5.5 not stated 2 walked not stated
11 not stated 0 walked not stated
12 not stated 0 walked not stated
12.1 not stated 0 walked not stated
12.2 not stated 0 walked not stated

Excluded sentences

SiteExcluded kindReasonQuote
3.6:1 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. If an error occurs but the type of the incoming packet cannot be determined, a packet with the identical cleartext header but with a sequence number incremented by one and the length set to zero MUST be returned to indicate an error.
3.7:3 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
Defines the word 'printable' used by the sentence the mapped id already carries; the same obligation on the same fields. The term "printable" used here means the fields MUST exclude the "Control Characters" defined in Section 5.2 of [RFC0020].
4.1:3 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
Restates the ban on TAC_PLUS_UNENCRYPTED_FLAG that the client-side row already carries. This option MUST NOT be used in production.
4.1:6 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. Implementations MUST allow control over maximum packet sizes accepted by TACACS+ Servers.
4.3:3 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. For example, a server MUST be configured to time out a Single Connection Mode TCP connection after a specific period of inactivity to preserve its resources.
4.5:1 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
The secrecy of the shared key, stated once here and once as an obligation on servers and clients in Section 10.5.1, which the mapped row carries. The secret keys MUST remain secret.
4.5:2 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. Server implementations MUST allow a unique secret key to be associated with each client.
4.5:3 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
The same obligation seen from the sender: the flag is set to 0 so the body is obfuscated, which is what the client row already requires. The flag field MUST be configured with TAC_PLUS_UNENCRYPTED_FLAG set to 0 so that the packet body is obfuscated by XORing it bytewise with a pseudo-random pad:
4.5:4 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. When a server detects that the secrets it has configured for the device do not match, it MUST return ERROR.
4.5:5 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
Restates the deprecation of the unencrypted option that the client row already carries. This option is deprecated and MUST NOT be used in production.
5.4.2:1 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. If the server does not implement an option, it MUST respond with TAC_PLUS_AUTHEN_STATUS_FAIL.
5.4.2.1:1 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. If the user does not include the username, then the server MUST obtain it from the client with a CONTINUE TAC_PLUS_AUTHEN_STATUS_GETUSER.
5.4.2.1:2 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. If the user does not provide a username, then the server can send another TAC_PLUS_AUTHEN_STATUS_GETUSER request, but the server MUST limit the number of retries that are permitted; the recommended limit is three attempts.
5.4.2.1:3 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. The data fields in both the START and CONTINUE packets are not used for ASCII logins; any content MUST be ignored.
5.4.2.2:3 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. The REPLY from the server MUST be either a PASS, FAIL, or ERROR.
5.4.2.3:2 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
The second half of the same CHAP START construction, which the mapped row states in full. The START packet MUST contain the username in the user field, and the data field is a concatenation of the PPP id, the challenge, and the response.
5.4.2.3:3 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. The REPLY from the server MUST be a PASS, FAIL, or ERROR.
5.4.2.4:2 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
The second half of the same MS-CHAP v1 START construction, which the mapped row states in full. The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response.
5.4.2.4:3 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. The REPLY from the server MUST be a PASS or FAIL.
5.4.2.4:4 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. The TACACS+ server MUST reject authentications where the challenge deviates from 8 bytes as defined in the RFC.
5.4.2.5:2 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
The second half of the same MS-CHAP v2 START construction, which the mapped row states in full. The START packet MUST contain the username in the user field, and the data field will be a concatenation of the PPP id, the MS-CHAP challenge, and the MS-CHAP response.
5.4.2.5:3 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. The REPLY from the server MUST be a PASS or FAIL.
5.4.2.5:4 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. The TACACS+ server MUST reject authentications where the challenge deviates from 16 bytes as defined in the RFC.
5.4.2.7:1 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. The status value TAC_PLUS_AUTHEN_STATUS_GETPASS MUST only be used when requesting the "new" password.
5.4.2.7:2 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. When requesting the "old" password, the status value MUST be set to TAC_PLUS_AUTHEN_STATUS_GETDATA.
6.1:1 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. As this information is not always subject to verification, it MUST NOT be used in policy evaluation.
6.2:4 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. When the status equals TAC_PLUS_AUTHOR_STATUS_FOLLOW, the arg_cnt MUST be 0.
7.2:1 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. The server MUST reply with success only when the accounting request has been recorded.
7.2:2 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. If the server did not record the accounting request, then it MUST reply with ERROR.
7.2:3 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. If the START flag is not set, then this indicates only that task is still running, and no new information is provided (servers MUST ignore any arguments).
7.2:5 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. The server MUST respond with TAC_PLUS_ACCT_STATUS_ERROR if the client requests an INVALID option.
8.1:2 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
The consequence clause of the same numeric-argument obligation, which the mapped row states in full. If the length cannot be accommodated, then the argument MUST be regarded as not handled and the logic in "Authorization" (Section 6.1) regarding the processing of arguments MUST be applied.
8.3:4 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. Servers MUST NOT make assumptions about the format of a task_id.
10.1:1 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the operator of the deployment, not to an implementation: the obligation is discharged by how the network is built and who may reach it. The producer would be the deploying network administrator, for whom Ze holds no code path, so no Ze function can satisfy or violate it. For these reasons, users deploying the TACACS+ protocol in their environments MUST limit access to known clients and MUST control the security of the entire transmission path.
10.2:2 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
Restates the ban on the TAC_PLUS_AUTHEN_STATUS_FOLLOW redirection that the mapped row carries. It MUST NOT be used outside a secured deployment.
10.5:1 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the operator of the deployment, not to an implementation: the obligation is discharged by how the network is built and who may reach it. The producer would be the deploying network administrator, for whom Ze holds no code path, so no Ze function can satisfy or violate it. With respect to the observations about the security issues described above, a network administrator MUST NOT rely on the obfuscation of the TACACS+ protocol.
10.5:2 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the operator of the deployment, not to an implementation: the obligation is discharged by how the network is built and who may reach it. The producer would be the deploying network administrator, for whom Ze holds no code path, so no Ze function can satisfy or violate it. TACACS+ MUST be used within a secure deployment; TACACS+ MUST be deployed over networks that ensure privacy and integrity of the communication and MUST be deployed over a network that is separated from other traffic.
10.5.1:2 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. TACACS+ servers MUST NOT leak sensitive data.
10.5.1:3 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. * TACACS+ servers MUST NOT expose shared secrets in logs.
10.5.1:4 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. * TACACS+ servers MUST allow a dedicated secret key to be defined for each client.
10.5.1:5 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. * TACACS+ server management systems MUST provide a mechanism to track secret key lifetimes and notify administrators to update them periodically.
10.5.1:7 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. * TACACS+ servers MUST support policy to define minimum complexity for shared keys.
10.5.2:1 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. TACACS+ servers MUST allow the definition of individual clients.
10.5.2:2 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. The servers MUST only accept network connection attempts from these defined known clients.
10.5.2:3 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. TACACS+ servers MUST reject connections that have TAC_PLUS_UNENCRYPTED_FLAG set.
10.5.2:4 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. There MUST always be a shared secret set on the server for the client requesting the connection.
10.5.2:5 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. If an invalid shared secret is detected when processing packets for a client, TACACS+ servers MUST NOT accept any new sessions on that connection.
10.5.2:6 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. TACACS+ servers MUST terminate the connection on completion of any sessions that were previously established with a valid shared secret on that connection.
10.5.2:9 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
Restates the production ban on TAC_PLUS_UNENCRYPTED_FLAG that the client row carries. This option MUST NOT be used when the client is in production.
10.5.3:1 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. To help TACACS+ administrators select stronger authentication options, TACACS+ servers MUST allow the administrator to configure the server to only accept challenge/response options for authentication (TAC_PLUS_AUTHEN_TYPE_CHAP or TAC_PLUS_AUTHEN_TYPE_MSCHAP or TAC_PLUS_AUTHEN_TYPE_MSCHAPV2 for authen_type).
10.5.3:2 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. If they must be implemented, the servers MUST default to the options being disabled and MUST warn the administrator that these options are not secure.
10.5.4:2 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
The same client obligation as Section 6.1: an unrecognized mandatory argument is evaluated as TAC_PLUS_AUTHOR_STATUS_FAIL. TACACS+ clients that receive an unrecognized mandatory argument MUST evaluate server response as if they received TAC_PLUS_AUTHOR_STATUS_FAIL.
10.5.5:1 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. TACACS+ servers MUST deprecate the redirection mechanism.
10.5.5:2 binds-another-role
never bound Ze
the obligation is addressed to a role Ze never acts as
Presumed wrong until justified: Ze rarely implements one side of a protocol, so the reason beside this row must name the role, show Ze never acts as it, and cite the producer that would.
Addressed to the TACACS+ server, the role that accepts connections, receives requests and returns replies. Ze implements the client (NAS) side only: internal/component/tacacs dials out, sends START/REQUEST packets and reads replies, and it never listens on port 49. The producer would be a TACACS+ server daemon, which Ze does not ship. If the redirection mechanism is implemented, then TACACS+ servers MUST disable it by default and MUST warn TACACS+ server administrators that it must only be enabled within a secure deployment due to the risks of revealing shared secrets.

Superseded

No document obsoletes RFC 8907, so its obligations are stated where they were written.