3. The TACACS+ packet header
All TACACS+ packets always begin with the following 12 byte header. The header is always cleartext and describes the remainder of the packet:
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
+----------------+----------------+----------------+----------------+ |major | minor | | | | |version| version| type | seq_no | flags | +----------------+----------------+----------------+----------------+ | | | session_id | +----------------+----------------+----------------+----------------+ | | | length | +----------------+----------------+----------------+----------------+
major_version
This is the major TACACS+ version number.
TAC_PLUS_MAJOR_VER := 0xc
minor_version
The minor TACACS+ version number. This is intended to allow revisions to the TACACS+ protocol while maintaining backwards compatibility.
Minor version 1 is currently defined for some commands. It may only be used for commands that explicitly call for it in this document. All other requests must use the default value.
TAC_PLUS_MINOR_VER_DEFAULT := 0x0
TAC_PLUS_MINOR_VER_ONE := 0x1
See the compatibility section at the end of the document.
When a daemon receives a packet with a minor_version that it does not support, it should return an ERROR status with the minor_version set to the closest supported value.
type
This is the packet type. Legal values are:
TAC_PLUS_AUTHEN := 0x01 (Authentication)
TAC_PLUS_AUTHOR := 0x02 (Authorization)
TAC_PLUS_ACCT := 0x03 (Accounting)
seq_no
This is the sequence number of the current packet for the current session. The first TACACS+ packet in a session MUST have the sequence number 1 and each subsequent packet will increment the sequence number by one. Thus clients only send packets containing odd sequence numbers, and TACACS+ daemons only send packets containing even sequence numbers.
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.
flags
This field contains various bitmapped flags.
The unencrypted flag bit says whether encryption is being used on the body of the TACACS+ packet (the entire portion after the header).
TAC_PLUS_UNENCRYPTED_FLAG := 0x01
If this flag is set, the packet is not encrypted. If this flag is cleared, the packet is encrypted.
Unencrypted packets are intended for testing, and are not recommended for normal use.
The single-connection flag:
TAC_PLUS_SINGLE_CONNECT_FLAG := 0x04
If a NAS sets this flag, this indicates that it supports multiplexing TACACS+ sessions over a single tcp connection. The flag need only be examined on the first two packets for any given connection since the single-connect status of a connection, once established, should not be changed. The connection must instead be closed and a new connec- tion opened, if required.
If the daemon sets this flag in the first reply packet in response to the first packet from a NAS, this indicates its willingness to sup- port single-connection over the current connection. The daemon may set this flag even if the NAS does not set it, but the NAS is under no obligation to honor it.
session_id
The Id for this TACACS+ session. The session id should be randomly chosen. This field does not change for the duration of the TACACS+ session. (If this value is not a cryptographically strong random number, it will compromise the protocol's security. [6])
length
The total length of the TACACS+ packet body (not including the header). This value is in network byte order. Packets are never pad- ded beyond this length.
4. The TACACS+ packet body
The TACACS+ body types are defined in the packet header. The remainder of this document will address the contents of the different TACACS+ bodies. The following general rules apply to all TACACS+ body types:
- The entire body is protected by the encryption mechanism indicated in the header.
- Any variable length data fields which are unused MUST have a length value equal to zero.
- Unused fixed length fields SHOULD have values of zero.
- All data and message fields in a TACACS+ packet MUST NOT be null terminated.
- All length values are unsigned and in network byte order.
- There should be no padding in any of the fields or at the end of a packet.
5. Body Encryption
The body of TACACS+ packets may be encrypted. The following sections describe the encryption mechanisms that are supported. Only one encryption mechanism SHOULD be used within a single session.
When the encryption mechanism relies on a secret key, it is referring to a shared secret value that is known to both the client and the daemon. This document does not discuss the management and storage of those keys. It is an implementation detail of the daemon and client, as to whether they will maintain only one key, or a different key for each client or daemon with which they communicate. For security rea- sons, the latter options should be available, but it is a site depen- dent decision as to whether the use of separate keys is appropriate.
The encrypted flag field may be set as follows:
TAC_PLUS_UNENCRYPTED_FLAG == 0x0
In this case, the packet body is encrypted by XOR-ing it byte-wise with a pseudo random pad.
ENCRYPTED {data} == data ^ pseudo_pad
The pad is generated by concatenating a series of MD5 hashes (each 16 bytes long) and truncating it to the length of the input data.
Whenever used in this document, MD5 refers to the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" as specified in [The MD5 Message-Digest Algorithm].
pseudo_pad = {MD5_1 [,MD5_2 [ ... ,MD5_n]]} truncated to len(data)
The first MD5 hash is generated by concatenating the session_id, the secret key, the version number and the sequence number and then run- ning MD5 over that stream. All of those input values are available in the packet header, except for the secret key which is a shared secret between the TACACS+ client and daemon.
The version number is the one byte combination of the major and minor version numbers.
The session id is used in the byte order in which it appears in the TACACS+ header. (i.e. in network byte order, not host byte order).
Subsequent hashes are generated by using the same input stream, but concatenating the previous hash value at the end of the input stream.
MD5_1 = MD5{session_id, key, version, seq_no}
MD5_2 = MD5{session_id, key, version, seq_no, MD5_1}
....
MD5_n = MD5{session_id, key, version, seq_no, MD5_n-1}
TAC_PLUS_UNENCRYPTED_FLAG == 0x1
In this case, the entire packet body is in cleartext. Encryption and decryption are null operations. This method should only be used for debugging. It does not provide data protection or authentication and is highly susceptible to packet spoofing. Implementing this encryp- tion method is optional.
NOTE: implementations should take care not to skip decryption simply because an incoming packet indicates that it is not encrypted.
After a packet body is decrypted, the lengths of the component values in the packet should be summed and checked against the cleartext datalength value from the header. Any packets which fail this check should be discarded and an error signalled. Commonly such failures may be expected to be seen when there are mismatched keys between the NAS and the TACACS+ server.
If an error must be declared but the type of the incoming packet can- not be determined, a packet with the identical cleartext header but with a sequence number incremented by one and the length set to zero may be returned to indicate an error.