RFC 4120

The Kerberos Network Authentication Service (V5)

๐Ÿ“… published July 2005, from ietf

RFC 4120: The Kerberos Network Authentication Service (V5) ๐Ÿ‘‘

okay bestie, let's get into it ๐Ÿซถ this one is RFC 4120, and it's all about Kerberos, the authentication service that helps systems confirm who's who ๐Ÿ”. It came out in July 2005 from the Network Working Group. The main authors are C. Neuman from USC-ISI, plus T. Yu, S. Hartman, and K. Raeburn, all from MIT ๐ŸŽ€. It's on the Standards Track, and it obsoletes RFC 1510, which was the earlier Kerberos spec ๐Ÿ’…


Status of This Memo โœจ

okay so this doc is an Internet standards track protocol for the Internet community ๐ŸŒธ They want feedback and suggestions for making it better ๐Ÿ’œ If you want to know where this protocol stands in the standardization process, check the current edition of "Internet Official Protocol Standards" (STD 1) ๐Ÿ“œ And the memo can be distributed freely, no limits ๐Ÿฆ‹

Copyright (C) The Internet Society (2005) โœจ

Abstract ๐Ÿฆ‹

so this document gives an overview and specification of Version 5 of the Kerberos protocol ๐Ÿ”ฅ It also obsoletes RFC 1510, because RFC 1510 needed some clearer explanations of how the protocol works and how it's supposed to be used ๐Ÿ™ˆ This doc is meant to be a detailed description you can actually implement, along with info on how to use the protocol messages and their fields properly ๐Ÿ’–

Table of Contents ๐Ÿ’…

   1. Introduction ....................................................5
      1.1. The Kerberos Protocol ......................................6
      1.2. Cross-Realm Operation ......................................8
      1.3. Choosing a Principal with Which to Communicate .............9
      1.4. Authorization .............................................10
      1.5. Extending Kerberos without Breaking Interoperability ......11
           1.5.1. Compatibility with RFC 1510 ........................11
           1.5.2. Sending Extensible Messages ........................12
      1.6. Environmental Assumptions .................................12
      1.7. Glossary of Terms .........................................13
   2. Ticket Flag Uses and Requests ..................................16
      2.1. Initial, Pre-authenticated, and
           Hardware-Authenticated Tickets ............................17
      2.2. Invalid Tickets ...........................................17
      2.3. Renewable Tickets .........................................17
      2.4. Postdated Tickets .........................................18
      2.5. Proxiable and Proxy Tickets ...............................19
      2.6. Forwardable Tickets .......................................19
      2.7. Transited Policy Checking .................................20
      2.8. OK as Delegate ............................................21
      2.9. Other KDC Options .........................................21
           2.9.1. Renewable-OK .......................................21
           2.9.2. ENC-TKT-IN-SKEY ....................................22
           2.9.3. Passwordless Hardware Authentication ...............22
   3. Message Exchanges ..............................................22
      3.1. The Authentication Service Exchange .......................22
           3.1.1. Generation of KRB_AS_REQ Message ...................24
           3.1.2. Receipt of KRB_AS_REQ Message ......................24
           3.1.3. Generation of KRB_AS_REP Message ...................24
           3.1.4. Generation of KRB_ERROR Message ....................27
           3.1.5. Receipt of KRB_AS_REP Message ......................27
           3.1.6. Receipt of KRB_ERROR Message .......................28
      3.2. The Client/Server Authentication Exchange .................29
           3.2.1. The KRB_AP_REQ Message .............................29
           3.2.2. Generation of a KRB_AP_REQ Message .................29
           3.2.3. Receipt of KRB_AP_REQ Message ......................30
           3.2.4. Generation of a KRB_AP_REP Message .................33
           3.2.5. Receipt of KRB_AP_REP Message ......................33
           3.2.6. Using the Encryption Key ...........................33
      3.3. The Ticket-Granting Service (TGS) Exchange ................34
           3.3.1. Generation of KRB_TGS_REQ Message ..................35
           3.3.2. Receipt of KRB_TGS_REQ Message .....................37
           3.3.3. Generation of KRB_TGS_REP Message ..................38
           3.3.4. Receipt of KRB_TGS_REP Message .....................42

      3.4. The KRB_SAFE Exchange .....................................42
           3.4.1. Generation of a KRB_SAFE Message ...................42
           3.4.2. Receipt of KRB_SAFE Message ........................43
      3.5. The KRB_PRIV Exchange .....................................44
           3.5.1. Generation of a KRB_PRIV Message ...................44
           3.5.2. Receipt of KRB_PRIV Message ........................44
      3.6. The KRB_CRED Exchange .....................................45
           3.6.1. Generation of a KRB_CRED Message ...................45
           3.6.2. Receipt of KRB_CRED Message ........................46
      3.7. User-to-User Authentication Exchanges .....................47
   4. Encryption and Checksum Specifications .........................48
   5. Message Specifications .........................................50
      5.1. Specific Compatibility Notes on ASN.1 .....................51
           5.1.1. ASN.1 Distinguished Encoding Rules .................51
           5.1.2. Optional Integer Fields ............................52
           5.1.3. Empty SEQUENCE OF Types ............................52
           5.1.4. Unrecognized Tag Numbers ...........................52
           5.1.5. Tag Numbers Greater Than 30 ........................53
      5.2. Basic Kerberos Types ......................................53
           5.2.1. KerberosString .....................................53
           5.2.2. Realm and PrincipalName ............................55
           5.2.3. KerberosTime .......................................55
           5.2.4. Constrained Integer Types ..........................55
           5.2.5. HostAddress and HostAddresses ......................56
           5.2.6. AuthorizationData ..................................57
           5.2.7. PA-DATA ............................................60
           5.2.8. KerberosFlags ......................................64
           5.2.9. Cryptosystem-Related Types .........................65
      5.3. Tickets ...................................................66
      5.4. Specifications for the AS and TGS Exchanges ...............73
           5.4.1. KRB_KDC_REQ Definition .............................73
           5.4.2. KRB_KDC_REP Definition .............................81
      5.5. Client/Server (CS) Message Specifications .................84
           5.5.1. KRB_AP_REQ Definition ..............................84
           5.5.2. KRB_AP_REP Definition ..............................88
           5.5.3. Error Message Reply ................................89
      5.6. KRB_SAFE Message Specification ............................89
           5.6.1. KRB_SAFE definition ................................89
      5.7. KRB_PRIV Message Specification ............................91
           5.7.1. KRB_PRIV Definition ................................91
      5.8. KRB_CRED Message Specification ............................92
           5.8.1. KRB_CRED Definition ................................92
      5.9. Error Message Specification ...............................94
           5.9.1. KRB_ERROR Definition ...............................94
      5.10. Application Tag Numbers ..................................96

   6. Naming Constraints .............................................97
      6.1. Realm Names ...............................................97
      6.2. Principal Names .......................................... 99
           6.2.1. Name of Server Principals .........................100
   7. Constants and Other Defined Values ............................101
      7.1. Host Address Types .......................................101
      7.2. KDC Messaging: IP Transports .............................102
           7.2.1. UDP/IP transport ..................................102
           7.2.2. TCP/IP Transport ..................................103
           7.2.3. KDC Discovery on IP Networks ......................104
      7.3. Name of the TGS ..........................................105
      7.4. OID Arc for KerberosV5 ...................................106
      7.5. Protocol Constants and Associated Values .................106
           7.5.1. Key Usage Numbers .................................106
           7.5.2. PreAuthentication Data Types ......................108
           7.5.3. Address Types .....................................109
           7.5.4. Authorization Data Types ..........................109
           7.5.5. Transited Encoding Types ..........................109
           7.5.6. Protocol Version Number ...........................109
           7.5.7. Kerberos Message Types ............................110
           7.5.8. Name Types ........................................110
           7.5.9. Error Codes .......................................110
   8. Interoperability Requirements .................................113
      8.1. Specification 2 ..........................................113
      8.2. Recommended KDC Values ...................................116
   9. IANA Considerations ...........................................116
   10. Security Considerations ......................................117
   11. Acknowledgements .............................................121
   A. ASN.1 Module ..................................................123
   B. Changes since RFC 1510 ........................................131
   Normative References .............................................134
   Informative References ...........................................135

1. Introduction ๐Ÿ’–

Okay bestie, this doc is all about the concepts and model that the Kerberos network authentication system is built on โœจ. It also spells out Version 5 of the Kerberos protocol ๐Ÿฆ‹. The why behind most design choices (motivations, goals, assumptions, rationale) only gets a quick glance here, since it's explained way more fully in a paper in IEEE communications [NT94] and, earlier, in the Kerberos part of the Athena Technical Plan [MNSS87].

This doc is NOT meant to explain Kerberos to end users, sysadmins, or app developers ๐Ÿ™ˆ. If you want higher-level reading, [NT94] covers Version 5 and [SNS88] documents version 4, and both are out there elsewhere ๐Ÿ“š.

Kerberos' model is partly based on Needham and Schroeder's trusted third-party authentication protocol [NS78], plus some modifications Denning and Sacco suggested [DS81] ๐Ÿง . The original design and implementation of Kerberos Versions 1 through 4 was done by two former Project Athena staff members, Steve Miller of Digital Equipment Corporation and Clifford Neuman (now at the Information Sciences Institute of the University of Southern California), along with Jerome Saltzer, Technical Director of Project Athena, and Jeffrey Schiller, MIT Campus Network Manager. Lots of other Project Athena folks helped with Kerberos too ๐Ÿซถ.

Version 5 (the one this doc describes) evolved because of new requirements and features that Version 4 just didn't have ๐Ÿ’…. Clifford Neuman and John Kohl led the design, with a ton of input from the community. At MIT, John Kohl and Theodore Ts'o led development of the MIT reference implementation, with help and contributed code from many others ๐Ÿ‘‘. Since RFC 1510 came out, lots of people have proposed extensions and revisions to the protocol. This doc reflects some of those proposals, and where a change took serious effort, it credits the person who proposed it ๐ŸŒธ.

Reference implementations of both Version 4 and Version 5 are publicly available, and commercial implementations have been developed and are widely used โœจ. The differences between Versions 4 and 5 are covered in [KNT94] ๐ŸŽ€.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119] ๐Ÿ”ฅ.

1.1. The Kerberos Protocol ๐Ÿ”

Kerberos provides a means of verifying the identities of principals (e.g., a workstation user or a network server) on an open (unprotected) network ๐ŸŒˆ. Here's the iconic part: it does this without relying on assertions by the host operating system, without basing trust on host addresses, without requiring physical security of all the hosts on the network, and under the assumption that packets traveling along the network can be read, modified, and inserted at will ๐Ÿ’€. It pulls this off as a trusted third-party authentication service using conventional (shared secret key) cryptography ๐Ÿงš. Extensions to Kerberos (outside the scope of this document) can provide for the use of public key cryptography during certain phases of the authentication protocol ๐Ÿ’œ. Those extensions support Kerberos authentication for users registered with public key certification authorities, and provide certain benefits of public key cryptography in situations where they're needed โœจ.

The basic Kerberos authentication process goes like this: A client sends a request to the authentication server (AS) for "credentials" for a given server. The AS responds with those credentials, encrypted in the client's key. The credentials consist of a "ticket" for the server and a temporary encryption key (often called a "session key"). The client transmits the ticket (which contains the client's identity and a copy of the session key, all encrypted in the server's key) to the server. The session key, now shared by the client and server, is used to authenticate the client and may optionally be used to authenticate the server ๐ŸŽ€. It may also be used to encrypt further communication between the two parties, or to exchange a separate sub-session key to be used to encrypt further communication ๐Ÿฆ‹. Note that many apps only use Kerberos' functions when they initiate a stream-based network connection. Unless an app performs encryption or integrity protection for the data stream, the identity verification only applies to initiating the connection, and it does NOT guarantee that subsequent messages on the connection come from the same principal ๐Ÿ˜ญ.

Implementation of the basic protocol consists of one or more authentication servers running on physically secure hosts. These servers maintain a database of principals (i.e., users and servers) and their secret keys ๐Ÿ”’. Code libraries provide encryption and implement the Kerberos protocol. To add authentication to its transactions, a typical network application adds calls to the Kerberos library directly, or goes through the Generic Security Services Application Programming Interface (GSS-API) described in a separate document [RFC4121] ๐Ÿ’…. These calls result in the transmission of the messages necessary to achieve authentication ๐Ÿ“.

The Kerberos protocol consists of several sub-protocols (or exchanges). There are two basic methods by which a client can ask a Kerberos server for credentials ๐Ÿง. In the first approach, the client sends a cleartext request for a ticket for the desired server to the AS. The reply is sent encrypted in the client's secret key. Usually this request is for a ticket-granting ticket (TGT), which can later be used with the ticket-granting server (TGS). In the second method, the client sends a request to the TGS. The client uses the TGT to authenticate itself to the TGS in the same manner as if it were contacting any other application server that requires Kerberos authentication. The reply is encrypted in the session key from the TGT ๐Ÿ‘‘. Though the protocol specification describes the AS and the TGS as separate servers, in practice they are implemented as different protocol entry points within a single Kerberos server ๐Ÿ™ˆ.

Once obtained, credentials may be used to verify the identity of the principals in a transaction, to ensure the integrity of messages exchanged between them, or to preserve privacy of the messages ๐ŸŒธ. The application is free to choose whatever protection may be necessary โœจ.

To verify the identities of the principals in a transaction, the client transmits the ticket to the application server. Because the ticket is sent "in the clear" (parts of it are encrypted, but this encryption doesn't thwart replay) and might be intercepted and reused by an attacker, additional information is sent to prove that the message originated with the principal to whom the ticket was issued ๐Ÿ•ต๏ธ. This information (called the authenticator) is encrypted in the session key and includes a timestamp โฐ. The timestamp proves that the message was recently generated and is not a replay. Encrypting the authenticator in the session key proves that it was generated by a party possessing the session key. Since no one except the requesting principal and the server know the session key (it is never sent over the network in the clear), this guarantees the identity of the client ๐Ÿซถ.

The integrity of the messages exchanged between principals can also be guaranteed by using the session key (passed in the ticket and contained in the credentials) ๐Ÿ”. This approach provides detection of both replay attacks and message stream modification attacks ๐Ÿšจ. It is accomplished by generating and transmitting a collision-proof checksum (elsewhere called a hash or digest function) of the client's message, keyed with the session key. Privacy and integrity of the messages exchanged between principals can be secured by encrypting the data to be passed by using the session key contained in the ticket or the sub-session key found in the authenticator ๐Ÿฆ‹.

The authentication exchanges mentioned above require read-only access to the Kerberos database. Sometimes, however, the entries in the database must be modified, such as when adding new principals or changing a principal's key ๐Ÿ› ๏ธ. This is done using a protocol between a client and a third Kerberos server, the Kerberos Administration Server (KADM). There is also a protocol for maintaining multiple copies of the Kerberos database. Neither of these protocols are described in this document ๐Ÿ™ˆ.

1.2. Cross-Realm Operation ๐ŸŒ

okay bestie, Kerberos is literally built to work across organizations ๐Ÿซถ A client in one org can get authenticated to a server in a totally different org. Every org that wants to run a Kerberos server sets up its own "realm" ๐Ÿฐ The realm a client is registered in is part of the client's name โœจ, and the end-service can use that name to decide whether to honor a request ๐Ÿ’…

So when two realms' admins set up "inter-realm" keys ๐Ÿ”‘, a client who's authenticated in their home realm can prove who they are to servers in the other realm. You can use a separate key for each direction (iykyk ๐Ÿ™ˆ). Exchanging them registers each realm's ticket-granting service as a principal in the other realm ๐Ÿ‘‘. Now the client can grab a TGT for the remote realm's ticket-granting service from their own local realm ๐ŸŽŸ๏ธ. When that TGT gets used, the remote ticket-granting service decrypts it with the inter-realm key, which is usually different from its own normal TGS key. That means it's certain the ticket came from the client's own TGS ๐Ÿ”. Tickets the remote ticket-granting service hands out will tell the end-service that the client was authenticated from another realm ๐Ÿฆ‹.

Without cross-realm operation, a client can (with the right permission) get a separately-named principal set up in a remote realm and do normal stuff with that realm's services. But even for small numbers of clients that gets super cumbersome ๐Ÿ˜ญ, so the more automatic methods described here are necessary.

A realm communicates with another realm if they share an inter-realm key, or if the local realm shares one with an intermediate realm that talks to the remote realm ๐Ÿ”—. An authentication path is just the sequence of intermediate realms you pass through to get from one realm to another ๐Ÿ›ค๏ธ.

Realms can be arranged hierarchically ๐ŸŒณ. Each realm shares a key with its parent and a different key with each child. If two realms don't directly share an inter-realm key, the hierarchy makes it pretty easy to build an authentication path ๐Ÿงš.

If there's no hierarchical organization, you might have to consult a database to build an authentication path between realms ๐Ÿ“š.

Even though realms are usually hierarchical, intermediate realms can be skipped to do cross-realm auth through alternate paths. (Those might be set up to make things between two realms more efficient โšก.) It really matters for the end-service to know which realms were transited when it decides how much faith to put in the auth ๐Ÿค”. So a field in each ticket holds the names of the realms that were involved in authenticating the client ๐Ÿ“.

The application server is ultimately responsible for accepting or rejecting authentication, and it SHOULD check the transited field ๐Ÿ›ก๏ธ. It can choose to rely on the Key Distribution Center (KDC) for its own realm to check the transited field instead. In that case, the application server's KDC sets the TRANSITED-POLICY-CHECKED flag. KDCs for intermediate realms can check the transited field too when they issue TGTs for other realms, but they're encouraged not to ๐Ÿ™ƒ. A client can ask the KDCs not to check the transited field by setting the DISABLE-TRANSITED-CHECK flag, and KDCs SHOULD honor this flag ๐Ÿซก.


1.3. Choosing a Principal with Which to Communicate ๐ŸŽฏ

Kerberos gives you a way to verify (subject to the assumptions in Section 1.6) that the entity you're talking to is the one registered with the KDC under the claimed identity (principal name) ๐Ÿ•ต๏ธ. You still have to figure out whether that identity is the entity you actually meant to talk to ๐Ÿคจ.

When the right data was exchanged in advance, the application can make that call syntactically, based on the application protocol spec, info the user gave, and config files ๐Ÿ“‹. For example, the server principal name (realm included) for a telnet server might come from the host name the user typed on the telnet command line, the host/ prefix from the application protocol spec, and a mapping to a Kerberos realm derived syntactically from the domain part of the host name plus info from the local Kerberos realms database ๐Ÿ—บ๏ธ.

You can also lean on trusted third parties for this, but only when the data they give you is suitably integrity-protected, both while it sits on their server and while it's being sent. So, for example, don't rely on an unprotected DNS record to map a host alias to a server's primary name and then accept that primary name as the party you meant to contact ๐Ÿšซ. An attacker can modify the mapping and impersonate the party, bestie ๐Ÿ˜ฑ.

Implementations of Kerberos and protocols based on Kerberos MUST NOT use insecure DNS queries to canonicalize the hostname components of service principal names (basically, they MUST NOT use insecure DNS queries to map one name to another and figure out the host part of the principal name you're about to talk to) ๐Ÿ™…โ€โ™€๏ธ

In an environment without a secure name service, application authors MAY append a statically configured domain name to unqualified hostnames before passing the name to the security mechanisms, but they should do no more than that ๐Ÿง. Secure name service facilities, if available, might be trusted for hostname canonicalization, but client-side canonicalization like that SHOULD NOT be required by KDC implementations ๐Ÿ”’.

Implementation note: Lots of current implementations canonicalize the provided service name in some way, often using DNS even though that creates security problems ๐Ÿ’€. But there's no consistency among them. Some case-fold the name to lowercase and some don't, and some use reverse resolution while others don't ๐Ÿคท. To maximize interoperability and security, applications SHOULD give security mechanisms names that result from folding the user-entered name to lowercase, without any other modifications or canonicalization โœจ.


1.4. Authorization ๐ŸŽ€

As an authentication service, Kerberos gives you a means of verifying the identity of principals on a network ๐Ÿชช. Authentication is usually most useful as the first step of authorization, which is figuring out whether a client may use a service, which objects it's allowed to access, and what type of access it gets for each one ๐Ÿ”. But Kerberos does not provide authorization by itself ๐Ÿ™…. Having a client ticket for a service only gets you authentication to that service. Without a separate authorization procedure, an application should not consider the ticket to authorize use of that service ๐Ÿšช.

Separate authorization methods MAY be implemented as application-specific access control functions. They may use files on the application server, separately issued authorization credentials (like ones based on proxies [Neu93]), or other authorization services ๐Ÿ—๏ธ. Separately authenticated authorization credentials MAY be embedded in a ticket's authorization data when they're encapsulated by the KDC-issued authorization data element ๐ŸŽ.

Applications should not accept the mere issuance of a service ticket by the Kerberos server (even by a modified Kerberos server) as granting authority to use the service โœ‹. Why? Because those apps may become vulnerable to bypassing this authorization check in an environment where other options for application authentication exist, or if they interoperate with other KDCs ๐Ÿ˜ฌ.


1.5. Extending Kerberos without Breaking Interoperability ๐Ÿงฉ

As the deployed base of Kerberos implementations grows, extending Kerberos gets more important ๐Ÿ“ˆ. Unfortunately, some extensions to the existing protocol create interoperability issues, because of uncertainty about how some implementations treat certain extensibility options ๐Ÿ˜ต. This section has guidelines that will help future implementations keep interoperating ๐Ÿซถ.

Kerberos has a general mechanism for protocol extensibility. Some protocol messages contain typed holes, which are sub-messages that contain an octet-string along with an integer that defines how to interpret that octet-string ๐Ÿง . The integer types are registered centrally, but they can be used both for vendor extensions and for extensions standardized through the IETF ๐ŸŒˆ.

In this document, the word "extension" refers to extension by defining a new type to insert into an existing typed hole in a protocol message. It doesn't refer to extension by adding new fields to ASN.1 types, unless the text explicitly indicates otherwise ๐Ÿ“.

1.5.1. Compatibility with RFC 1510 ๐Ÿ“œ

Existing Kerberos message formats can't readily be extended by adding fields to the ASN.1 types ๐Ÿ™…. Sending extra fields often gets the entire message discarded without any error indication ๐Ÿ’€. Future versions of this specification will give guidelines to make sure ASN.1 fields can be added without creating an interoperability problem ๐Ÿ”ฎ.

In the meantime, all new or modified implementations of Kerberos that receive an unknown message extension SHOULD preserve the encoding of the extension but otherwise ignore its presence ๐Ÿซถ. Recipients MUST NOT decline a request simply because an extension is present ๐Ÿ™Œ.

There's one exception to this rule. If an unknown authorization data element type is received by a server other than the ticket-granting service, either in an AP-REQ or in a ticket contained in an AP-REQ, then authentication MUST fail ๐Ÿšจ. One of the main uses of authorization data is restricting the use of the ticket. If the service can't determine whether the restriction applies to it, a security weakness may result if the ticket can be used for that service ๐Ÿ˜ฑ.

Authorization elements that are optional SHOULD be enclosed in the AD-IF-RELEVANT element ๐ŸŽ€.

The ticket-granting service MUST ignore but propagate to derivative tickets any unknown authorization data types, unless those data types are embedded in a MANDATORY-FOR-KDC element, in which case the request will be rejected ๐Ÿšซ. This behavior makes sense because requiring the ticket-granting service to understand unknown authorization data types would mean KDC software has to be upgraded to understand new application-level restrictions before applications use them. That would decrease the usefulness of authorization data as a way to restrict ticket use ๐Ÿ“‰. No security problem is created, because the services the tickets are issued to will verify the authorization data ๐Ÿ›ก๏ธ.

Implementation note: Many RFC 1510 implementations ignore unknown authorization data elements. Depending on these implementations to honor authorization data restrictions may create a security weakness ๐Ÿฅบ

1.5.2. Sending Extensible Messages โœจ

okay so old implementations need to be able to understand messages sent to them, even if they don't understand an extension that's being used ๐Ÿ’… Unless the sender knows an extension is supported, that extension can't change the semantics of the core message or the extensions that were already defined ๐Ÿ™ˆ

for example, an extension that includes the key info needed to decrypt the encrypted part of a KDC-REP could only be used when the recipient is known to support it ๐Ÿ” so when you design these, you have to give the recipient a way to tell the sender it supports the extension ๐Ÿซถ like, if an extension changes the KDC-REP reply key, the client can signal support by including a padata element in the AS-REQ sequence ๐ŸŽ€ the KDC should only use the extension if that padata element is there in the AS-REQ ๐Ÿ’– even if policy says the extension is required, it's better to return an error saying so than to use it when the recipient might not support it ๐Ÿ˜ญ debugging implementations that don't interoperate is way easier when errors actually get returned ๐Ÿงš

1.6. Environmental Assumptions ๐ŸŒธ

Kerberos has a few assumptions about the environment it needs to work properly, and they're lowkey important, so let's go ๐Ÿ‘‘

  • "Denial of service" attacks aren't solved by Kerberos ๐Ÿ’€ There are spots in the protocols where an intruder can stop an application from taking part in the proper authentication steps. Spotting and fixing those attacks (some of which can look like totally normal failure modes for the system) is usually best left to the human admins and users ๐Ÿ™ˆ
  • Principals MUST keep their secret keys secret ๐Ÿ”ฅ If an intruder steals a principal's key, they can masquerade as that principal, or impersonate any server to the legit principal. Not me being dramatic, this is serious ๐Ÿ˜ญ
  • "Password guessing" attacks aren't solved by Kerberos either ๐Ÿ’… If a user picks a weak password, an attacker can run an offline dictionary attack: they keep trying to decrypt messages they've grabbed, which are encrypted under a key derived from the user's password, using entries from a dictionary ๐Ÿฆ‹
  • Each host on the network MUST have a clock that's "loosely synchronized" with the other hosts' clocks โฐ This synchronization is used to cut down on the bookkeeping application servers need for replay detection. The amount of "looseness" can be configured per server, but it's typically around 5 minutes โœจ If the clocks are synchronized over the network, the clock synchronization protocol MUST itself be secured from network attackers ๐Ÿ›ก๏ธ
  • Principal identifiers aren't recycled on a short-term basis ๐ŸŽ€ A common way to do access control is with access control lists (ACLs) that grant permissions to particular principals. If a stale ACL entry sticks around for a deleted principal, and that principal identifier gets reused, the new principal would inherit the rights in the stale entry ๐Ÿ˜ณ Not reusing principal identifiers removes the danger of accidental access ๐Ÿซถ

1.7. Glossary of Terms ๐Ÿ“–

Here's a list of terms used all through this document, so you're never lost ๐Ÿงš

Authentication Verifying the claimed identity of a principal. โœ…

Authentication header A record containing a Ticket and an Authenticator, presented to a server as part of the authentication process. ๐ŸŽŸ๏ธ

Authentication path A sequence of intermediate realms that get transited during the authentication process when you're communicating from one realm to another. ๐Ÿ›ค๏ธ

Authenticator A record with info that can be shown to have been recently generated using the session key that only the client and server know. ๐Ÿ”‘

Authorization The process of figuring out whether a client may use a service, which objects the client can access, and what type of access is allowed for each. ๐Ÿ‘‘

Capability A token that grants the bearer permission to access an object or service. In Kerberos, this might be a ticket whose use is restricted by the contents of the authorization data field, but which lists no network addresses, together with the session key needed to use the ticket. ๐ŸŽซ

Ciphertext The output of an encryption function. Encryption turns plaintext into ciphertext. ๐Ÿ”

Client A process that uses a network service on behalf of a user. Note that in some cases a Server may itself be a client of some other server (for example, a print server may be a client of a file server). ๐Ÿ’ป

Credentials A ticket plus the secret session key needed to use that ticket successfully in an authentication exchange. ๐Ÿชช

Encryption Type (etype) When it's attached to encrypted data, an encryption type tells you which algorithm was used to encrypt the data, and it's used to pick the right algorithm for decrypting it ๐Ÿงฉ Encryption type tags get passed around in other messages to list algorithms that are desired, supported, preferred, or allowed for encrypting data between parties. That preference gets combined with local info and policy to choose the algorithm that actually gets used โœจ

KDC Key Distribution Center ๐Ÿฐ A network service that supplies tickets and temporary session keys, or an instance of that service, or the host it runs on. The KDC services both initial ticket and ticket-granting ticket requests. The initial ticket portion is sometimes called the Authentication Server (or service), and the ticket-granting ticket portion is sometimes called the ticket-granting server (or service). ๐ŸŽ€

Kerberos The name given to Project Athena's authentication service, the protocol that service uses, or the code that implements it. The name comes from the three-headed dog that guards Hades ๐Ÿ•โ€๐Ÿฆบ๐Ÿ”ฅ

Key Version Number (kvno) A tag attached to encrypted data that says which key was used for encryption when a long-lived key tied to a principal changes over time ๐Ÿ”„ It's used during the transition to a new key, so whoever decrypts a message can tell whether the data was encrypted with the old key or the new one ๐Ÿ—๏ธ

Plaintext The input to an encryption function, or the output of a decryption function. Decryption turns ciphertext back into plaintext ๐Ÿ”“

Principal A named client or server entity that takes part in a network communication, with one name considered canonical ๐Ÿ‘ค

Principal identifier The canonical name used to uniquely identify each different principal ๐Ÿ†”

Seal To encipher a record with several fields in a way that the fields can't be individually replaced without knowing the encryption key, or without leaving evidence of tampering ๐Ÿซ™

Secret key An encryption key shared by a principal and the KDC, distributed outside the bounds of the system, with a long lifetime. For a human user's principal, the secret key MAY be derived from a password ๐Ÿคซ

Server A particular Principal that provides a resource to network clients. The server is sometimes called the Application Server ๐Ÿ–ฅ๏ธ

Service A resource provided to network clients, often provided by more than one server (remote file service is a classic example) ๐Ÿ—‚๏ธ

Session key A temporary encryption key used between two principals, lasting only as long as a single login "session". In the Kerberos system, the KDC generates the session key. It's different from the sub-session key, which comes next ๐ŸŒ™

Sub-session key A temporary encryption key used between two principals, selected and exchanged by the principals using the session key, and lasting only as long as a single association. It's also called the subkey ๐Ÿง

Ticket A record that helps a client authenticate itself to a server. It contains the client's identity, a session key, a timestamp, and other info, all sealed using the server's secret key ๐ŸŽŸ๏ธ It only authenticates a client when it's presented along with a fresh Authenticator ๐Ÿ’…

2. Ticket Flag Uses and Requests ๐Ÿšฉ

Every Kerberos ticket has a set of flags that describe its attributes โœจ Most flags can be requested by a client when the ticket is obtained, and some get turned on and off automatically by a Kerberos server when needed ๐Ÿค– The sections below explain what the flags mean and give examples of why you'd use them ๐Ÿ’– Apart from the INVALID flag, clients MUST ignore ticket flags they don't recognize ๐Ÿ™ˆ KDCs MUST ignore KDC options they don't recognize too ๐Ÿซถ Some RFC 1510 implementations are known to reject unknown KDC options, so clients may need to resend a request without the new KDC options if it got rejected when those options were added after RFC 1510 ๐Ÿ˜ญ Because new KDCs ignore unknown options, clients MUST confirm that the ticket the KDC returns actually meets their needs ๐Ÿ”

Heads up: it's generally not possible to tell whether an option wasn't honored because the KDC didn't understand it, or because it was rejected by configuration or policy ๐Ÿซ  When you add a new option to Kerberos, designers should consider whether that distinction matters for their option. If it does, the spec of the option needs to provide a way for the KDC to say the option was understood but rejected. Usually that mechanism has to be broad enough to return an error or a reason ๐Ÿ’…

2.1. Initial, Pre-authenticated, and Hardware-Authenticated Tickets ๐ŸŽซ

The INITIAL flag means a ticket was issued using the AS protocol, rather than being issued based on a TGT ๐ŸŒฑ Application servers that want proof the client knows its secret key (like a password-changing program) can insist that this flag is set on any tickets they accept. That way they can be sure the client's key was recently presented to the authentication server ๐Ÿ”

The PRE-AUTHENT and HW-AUTHENT flags give extra info about the initial authentication ๐Ÿง  This is true whether the current ticket was issued directly (in which case INITIAL will also be set) or issued based on a TGT (in which case the INITIAL flag is clear, but PRE-AUTHENT and HW-AUTHENT are carried forward from the TGT) ๐Ÿฆ‹

2.2. Invalid Tickets ๐Ÿšซ

The INVALID flag means a ticket is invalid. Application servers MUST reject tickets that have this flag set ๐Ÿ™…โ€โ™€๏ธ A postdated ticket gets issued in this form. Invalid tickets MUST be validated by the KDC before use, by presenting them to the KDC in a TGS request with the VALIDATE option specified ๐Ÿซถ The KDC only validates tickets after their starttime has passed ๐Ÿ•ฐ๏ธ The validation is required so that postdated tickets stolen before their starttime can be made permanently invalid (through a hot-list mechanism) (see Section 3.3.3.1) ๐Ÿ”ฅ Main character energy for security, honestly ๐Ÿ‘‘

2.3. Renewable Tickets โœจ

okay so apps sometimes want tickets that stay valid for super long stretches ๐Ÿ•ฐ๏ธ, but that's kinda risky bc if someone steals one, it works until it expires ๐Ÿ˜ญ. Grabbing short-lived tickets over and over sounds safer, but then the client needs long-term access to its secret key, and that's an even bigger risk ๐Ÿ’€. Enter renewable tickets ๐Ÿฆ‹, which help limit the damage from theft.

Renewable tickets have two "expiration times." The first is when the current instance of the ticket expires. The second is the latest permissible value for an individual expiration time. So an application client has to keep refreshing (i.e., before it expires) by presenting a renewable ticket to the KDC with the RENEW option set in the KDC request ๐Ÿ’Œ. The KDC then issues a new ticket with a new session key and a later expiration time ๐ŸŒธ. Every other field stays the same during renewal. Once the latest permissible expiration time arrives, the ticket expires for good ๐Ÿชฆ. At each renewal, the KDC MAY consult a hot-list to check whether the ticket was reported stolen since its last renewal. If it was, the KDC will refuse to renew it, so stolen tickets get a much shorter usable life ๐Ÿšซ.

The RENEWABLE flag is normally only interpreted by the ticket-granting service (discussed below in Section 3.3). Application servers can usually ignore it. However, some particularly careful application servers MAY disallow renewable tickets ๐Ÿง.

If a renewable ticket isn't renewed by its expiration time, the KDC won't renew it. The RENEWABLE flag is reset by default, but a client MAY request that it be set by setting the RENEWABLE option in the KRB_AS_REQ message ๐ŸŽ€. If it's set, then the renew-till field in the ticket holds the time after which the ticket may not be renewed โณ.


2.4. Postdated Tickets ๐Ÿงš

sometimes apps need tickets for way later, like a batch submission system that needs tickets to be valid when the batch job actually gets serviced ๐Ÿ“ฆ. But holding valid tickets in a batch queue is risky, since they're online longer and more prone to theft ๐Ÿ‘€. Postdated tickets fix this ๐Ÿ’…. You get them from the KDC at job submission time, but they stay "dormant" until they're activated and validated by a further request to the KDC. If a theft got reported in the meantime, the KDC would refuse to validate the ticket, and the thief is foiled ๐Ÿ™…โ€โ™€๏ธโœจ.

The MAY-POSTDATE flag is normally only interpreted by the ticket-granting service. Application servers can ignore it. This flag MUST be set in a TGT in order to issue a postdated ticket based on the presented ticket ๐Ÿ”‘. It's reset by default, but a client MAY request it by setting the ALLOW-POSTDATE option in the KRB_AS_REQ message. This flag does NOT let a client get a postdated TGT. Postdated TGTs can only be obtained by requesting the postdating in the KRB_AS_REQ message ๐Ÿ™ƒ.

The life (endtime-starttime) of a postdated ticket will be the remaining life of the TGT at request time. The exception is when the RENEWABLE option is also set. Then it can be the full life (endtime-starttime) of the TGT ๐ŸŒˆ. The KDC MAY limit how far in the future a ticket may be postdated ๐Ÿ“….

The POSTDATED flag shows that a ticket has been postdated. The application server can check the authtime field in the ticket to see when the original authentication happened ๐Ÿ•ต๏ธโ€โ™€๏ธ. Some services MAY choose to reject postdated tickets, or they may only accept them within a certain period after the original authentication. When the KDC issues a POSTDATED ticket, it'll also be marked as INVALID, so the application client MUST present the ticket to the KDC to be validated before use ๐Ÿซถ.


2.5. Proxiable and Proxy Tickets ๐ŸŽญ

sometimes a principal needs to let a service do something on its behalf. The service has to be able to take on the client's identity, but only for one particular purpose ๐ŸŽฏ. A principal can allow this by granting the service a proxy.

Granting a proxy with the proxy and proxiable flags is how you get credentials for specific services. It's kinda a proxy too, but users who want to delegate their identity in a form that works for ALL purposes MUST use the ticket forwarding mechanism described in the next section to forward a TGT ๐Ÿ—๏ธ.

The PROXIABLE flag is normally only interpreted by the ticket-granting service. Application servers can ignore it. When it's set, it tells the ticket-granting server that it's OK to issue a new ticket (but not a TGT) with a different network address based on this ticket ๐Ÿ’โ€โ™€๏ธ. This flag is set if the client requests it on initial authentication. By default, the client asks for it to be set when requesting a TGT, and asks for it to be reset when requesting any other ticket ๐Ÿ”.

This flag lets a client pass a proxy to a server so it can make a remote request on the client's behalf. Like, a print service client can give the print server a proxy to access the client's files on a particular file server so the print job can go through ๐Ÿ–จ๏ธ๐Ÿ“.

Kerberos tickets are often only valid from the network addresses included in them, which makes stolen credentials harder to use ๐Ÿงฑ. It's also allowed as a policy option to allow requests and issue tickets with no network addresses specified. When granting a proxy, the client MUST specify the new network address the proxy will be used from, OR say that the proxy is for use from any address ๐ŸŒ.

The PROXY flag gets set in a ticket by the TGS when it issues a proxy ticket. Application servers MAY check this flag. They can also, at their option, MAY require additional authentication from the agent presenting the proxy, which gives them an audit trail ๐Ÿ•ต๏ธ.


2.6. Forwardable Tickets ๐Ÿฆ‹

authentication forwarding is a kind of proxy where the service gets COMPLETE use of the client's identity ๐Ÿชช. Example: a user logs in to a remote system and wants authentication to work from there like the login was local ๐Ÿ .

The FORWARDABLE flag is normally only interpreted by the ticket-granting service. Application servers can ignore it. It works a lot like PROXIABLE, except TGTs can also be issued with different network addresses ๐ŸŒ. The flag is reset by default, but users MAY request that it be set by setting the FORWARDABLE option in the AS request when they ask for their initial TGT ๐Ÿ’œ.

This flag lets authentication be forwarded without the user having to type their password again ๐Ÿ™Œ. If the flag isn't set, authentication forwarding isn't allowed. You can still get the same result if the user goes through the AS exchange, specifies the requested network addresses, and supplies a password ๐Ÿ”.

The TGS sets the FORWARDED flag when a client presents a ticket with FORWARDABLE set and asks for a forwarded ticket by specifying the FORWARDED KDC option and giving a set of addresses for the new ticket ๐Ÿ“จ. It's also set in all tickets issued based on tickets with the FORWARDED flag set. Application servers may choose to process FORWARDED tickets differently from non-FORWARDED tickets ๐Ÿ‘€.

If addressless tickets get forwarded from one system to another, clients SHOULD still use this option to get a new TGT, so the different systems end up with different session keys ๐Ÿ”‘โœจ.


2.7. Transited Policy Checking ๐Ÿ•ต๏ธโ€โ™€๏ธ

in Kerberos, the application server is ultimately responsible for accepting or rejecting authentication. It SHOULD check that only suitably trusted KDCs are relied on to authenticate a principal ๐Ÿง. The transited field in the ticket says which realms (and therefore which KDCs) were involved in the authentication process, and an application server would normally check it ๐Ÿ“‹. If any of those are untrusted to authenticate the client principal (usually decided by a realm-based policy), the authentication attempt MUST be rejected ๐Ÿšซ. Having trusted KDCs on that list doesn't guarantee anything, though, bc an untrusted KDC could have faked the list ๐Ÿ’€.

Even though the end server makes the final call, the KDC for the end server's realm MAY apply a realm-specific policy for validating the transited field and accepting credentials for cross-realm authentication. When the KDC runs those checks and accepts the cross-realm authentication, it sets the TRANSITED-POLICY-CHECKED flag in the service tickets it issues based on the cross-realm TGT ๐ŸŽŸ๏ธ. A client MAY ask the KDCs not to check the transited field by setting the DISABLE-TRANSITED-CHECK flag. KDCs are encouraged but not required to honor this flag ๐Ÿคทโ€โ™€๏ธ.

Application servers MUST either do the transited-realm checks themselves, or reject cross-realm tickets without TRANSITED-POLICY-CHECKED set ๐Ÿ›ก๏ธ.


2.8. OK as Delegate ๐Ÿ’Œ

sometimes a client needs to give a server the authority to act on its behalf when it contacts other services ๐Ÿ“ฌ. That means the client forwards credentials to an intermediate server. Being able to get a service ticket for a server tells the client NOTHING about whether that server should be trusted to accept delegated credentials ๐Ÿ™…โ€โ™€๏ธ. The OK-AS-DELEGATE flag gives the KDC a way to share local realm policy with the client about whether an intermediate server can be trusted with those credentials ๐Ÿซก.

The copy of the ticket flags in the encrypted part of the KDC reply may have the OK-AS-DELEGATE flag set. That tells the client the realm's policy has decided the server named in the ticket is a suitable recipient of delegation โœ…. The client can use that flag to help decide whether to delegate credentials (grant either a proxy or a forwarded TGT) to this server ๐Ÿค”. It's totally acceptable to ignore the value of this flag. When setting it, an administrator should think about the security and placement of the server where the service runs, plus whether the service even needs delegated credentials ๐Ÿ—๏ธ.


2.9. Other KDC Options ๐ŸŒธ

there are three additional options that MAY be set in a client's request to the KDC. Here's the first one ๐Ÿ‘‡.

2.9.1. Renewable-OK ๐Ÿ’–

The RENEWABLE-OK option says the client will accept a renewable ticket if a ticket with the requested life can't be provided any other way ๐Ÿ™. If that's the case, the KDC MAY issue a renewable ticket with a renew-till equal to the requested endtime ๐Ÿ’ซ. The value of the renew-till field MAY still be adjusted by site-determined limits, or by limits imposed by the individual principal or server ๐Ÿ”ง.

2.9.2. ENC-TKT-IN-SKEY โœจ

okay so basic Kerberos is giving client-server energy ๐ŸŽ€ and it's not really built for peer-to-peer, because the user's long-term key doesn't stick around on the workstation after initial login ๐Ÿ˜ญ. peers can still get authenticated though, through the user-to-user variant ๐Ÿซถ. the ENC-TKT-IN-SKEY option is how that works: it lets the KDC issue a service ticket encrypted with the session key from another TGT that was issued to a different user ๐Ÿ’…. only the ticket-granting service honors this one ๐Ÿ‘‘. it basically says the ticket for the end server should be encrypted in the session key from the extra second TGT that came along with the request. check Section 3.3.3 for the deets ๐Ÿงš

2.9.3. Passwordless Hardware Authentication

OPT-HARDWARE-AUTH means the client wants some kind of hardware authentication, either instead of or on top of its password or other long-lived encryption key ๐Ÿ”. only the authentication service honors this one ๐Ÿ™Œ. if it's supported and policy allows it, the KDC sends back KDC_ERR_PREAUTH_REQUIRED along with the required METHOD-DATA for doing that authentication ๐Ÿ“.


3. Message Exchanges ๐Ÿฆ‹

these sections are all about how clients and servers talk to each other and which messages get passed back and forth ๐Ÿ’ฌ.

3.1. The Authentication Service Exchange

Summary

         Message direction       Message type    Section
         1. Client to Kerberos   KRB_AS_REQ      5.4.1
         2. Kerberos to client   KRB_AS_REP or   5.4.2
                                 KRB_ERROR       5.9.1

okay so the Authentication Service (AS) Exchange happens between the client and the Kerberos Authentication Server, and a client starts it when it wants credentials for a server but doesn't have any yet ๐ŸŽซ. in its basic form it uses the client's secret key for encryption and decryption ๐Ÿ”‘. this is usually how a login session kicks off: you grab credentials for a Ticket-Granting Server, and that one gets you credentials for other servers (see Section 3.3) without needing your secret key again ๐Ÿ™Œ. it's also used for services that must not go through the Ticket-Granting Service and need you to prove you know a principal's secret key, like the password-changing service ๐Ÿ”’. that one denies requests unless you can show your old password, because otherwise someone walking up to an unattended session could change your password ๐Ÿ™ˆ.

this exchange doesn't prove who the user is by itself ๐Ÿšจ. to log a user in locally, the AS credentials can first be used in a TGS exchange to get credentials for a local server, and then those credentials have to be verified by a local server through a successful Client/Server exchange โœ….

the AS exchange has two messages: KRB_AS_REQ from the client to Kerberos, and KRB_AS_REP or KRB_ERROR back in reply. the formats are in Sections 5.4.1, 5.4.2, and 5.9.1 ๐Ÿ“œ.

in the request, the client sends (in cleartext) its own identity, the identity of the server it wants credentials for, other info about those credentials, and a randomly generated nonce ๐ŸŽฒ. the nonce can be used to detect replays and to match replies with their requests. this nonce MUST be generated randomly by the client and remembered so it can be checked against the nonce in the expected reply ๐Ÿง . the response, KRB_AS_REP, has a ticket for the client to show the server, plus a session key that the client and server will share ๐Ÿค. the session key and extra info are encrypted in the client's secret key ๐Ÿ”. the encrypted part of KRB_AS_REP also contains the nonce, which MUST be matched with the nonce from the KRB_AS_REQ message โœจ.

without pre-authentication, the authentication server doesn't know whether the client is actually the principal named in the request ๐Ÿคทโ€โ™€๏ธ. it just sends a reply without knowing or caring whether they're the same. that's fine because nobody except the principal named in the request can use the reply, since the critical info is encrypted in that principal's key ๐Ÿ—๏ธ. but an attacker can send a KRB_AS_REQ message to get known plaintext and go after the principal's key ๐Ÿ˜ฑ. especially if the key is based on a password, that's a real security exposure ๐Ÿ’€. so the initial request has an optional field that can pass extra info the initial exchange might need. this field SHOULD be used for pre-authentication, as described in sections 3.1.1 and 5.2.7 ๐Ÿ›ก๏ธ.

various errors can happen, and they show up as a KRB_ERROR response instead of KRB_AS_REP ๐Ÿ™ƒ. the error message is not encrypted. the KRB_ERROR message has info that helps associate it with the message it replies to. its contents aren't integrity-protected, so the client can't detect replays, fabrications, or modifications ๐Ÿซฃ. a fix for this will be included in a future version of the protocol ๐Ÿ”ฎ.

3.1.1. Generation of KRB_AS_REQ Message

the client can set a bunch of options in the initial request ๐ŸŽ€. these include whether pre-authentication is performed, whether the requested ticket is renewable, proxiable, or forwardable, and whether it should be postdated or allow postdating of derivative tickets ๐Ÿ“…. they also include whether a renewable ticket will be accepted in place of a non-renewable one, if the requested expiration date can't be met by a non-renewable ticket because of configuration constraints โš™๏ธ.

the client prepares the KRB_AS_REQ message and sends it to the KDC ๐Ÿ“จ.

3.1.2. Receipt of KRB_AS_REQ Message

if all goes well, processing the KRB_AS_REQ message creates a ticket for the client to present to the server ๐ŸŽŸ๏ธ. the format is in Section 5.3 ๐Ÿ’ซ.

because Kerberos can run over unreliable transports like UDP, the KDC MUST be prepared to retransmit responses in case they get lost ๐Ÿ”. if a KDC gets a request identical to one it recently processed successfully, the KDC MUST respond with a KRB_AS_REP message rather than a replay error ๐Ÿ™Œ. to reduce the ciphertext given to a potential attacker, KDCs MAY send the same response that was generated when the request was first handled ๐Ÿค. KDCs MUST obey this replay behavior even if the actual transport in use is reliable ๐Ÿซถ.

3.1.3. Generation of KRB_AS_REP Message โœจ

Okay bestie, the authentication server (aka the KDC, the main character here ๐Ÿ‘‘) starts by looking up the client and server principals named in the KRB_AS_REQ in its database and pulling out their keys ๐Ÿ”‘. If the client principal in the request doesn't exist in the KDC's principal database, it sends back KDC_ERR_C_PRINCIPAL_UNKNOWN. ๐Ÿ’€

Next, if the server is supposed to pre-authenticate the request, it does. If that check fails, you get KDC_ERR_PREAUTH_FAILED. ๐Ÿ™ˆ If pre-auth is required but the request didn't include it, you get KDC_ERR_PREAUTH_REQUIRED, and a METHOD-DATA object goes in the e-data field of the KRB-ERROR to say which pre-auth mechanisms are acceptable. Usually that includes PA-ETYPE-INFO and/or PA-ETYPE-INFO2 elements, as described below. And if the server can't support any encryption type the client asked for, it's KDC_ERR_ETYPE_NOSUPP time ๐Ÿ˜ญ

Then comes the fun part: the KDC makes a 'random' session key. That means, among other things, it should be impossible to guess the next session key from the past ones ๐Ÿ”. A pseudo-random number generator can do this if it's built on cryptographic principles, but it's way more iconic to use a truly random number generator, like one based on measurements of random physical phenomena ๐ŸŒˆ. For the full tea on randomness, check out [RFC4086].

When there are multiple encryption keys registered for a client in the Kerberos database, the KDC uses the etype field from the AS request to pick the encryption method that protects the encrypted part of the KRB_AS_REP message going back to the client. If there's more than one supported strong encryption type in the etype list, the KDC SHOULD use the first valid strong etype that has an encryption key available ๐Ÿ’…

When the user's key comes from a password or pass phrase, the string-to-key function for that encryption key type is used, as specified in [RFC3961] โœจ. The salt and the extra parameters for that function have default values (set by Section 4 and by the encryption mechanism spec, respectively), but pre-authentication data (PA-PW-SALT, PA-AFS3-SALT, PA-ETYPE-INFO, PA-ETYPE-INFO2, etc.) can override them. Since the KDC is presumed to store only a copy of the resulting key, these values should not be changed for password-based keys, except when changing the principal's key ๐Ÿซถ

When the AS server includes pre-authentication data in a KRB-ERROR or an AS-REP, it MUST use PA-ETYPE-INFO2, not PA-ETYPE-INFO, if the etype field of the client's AS-REQ lists at least one "newer" encryption type. Otherwise, when the etype field doesn't list any "newer" encryption types, it MUST send both PA-ETYPE-INFO2 and PA-ETYPE-INFO, with an entry for each enctype ๐Ÿฆ‹. A "newer" enctype is any enctype first officially specified at the same time as, or after, the issue of this RFC. DES, 3DES, RC4, and anything defined in [RFC1510] are NOT "newer" enctypes ๐Ÿ™ƒ

Also, you can't reliably generate a user's key from a pass phrase without contacting the KDC, because nobody can know ahead of time whether alternate salt or parameter values are needed ๐Ÿ”

The KDC tries to assign the type of the random session key from the list of methods in the etype field. It picks the right type using that list plus info from the Kerberos database about which encryption methods are acceptable for the application server. The KDC will not issue tickets with a weak session key encryption type ๐Ÿšซ

If the requested starttime is absent, points to the past, or is within the acceptable clock skew for the KDC, and the POSTDATE option hasn't been specified, then the ticket's starttime is set to the authentication server's current time โฐ. If it points to the future beyond the acceptable clock skew, but the POSTDATED option hasn't been specified, you get KDC_ERR_CANNOT_POSTDATE. Otherwise, the requested starttime gets checked against the local realm's policy, since the administrator might ban certain types or ranges of postdated tickets. If the starttime is acceptable, it's set as requested and the INVALID flag is set in the new ticket ๐ŸŒธ. A postdated ticket MUST be validated before use, by presenting it to the KDC after the starttime has been reached.

The expiration time of the ticket is set to the earlier of the requested endtime and a time determined by local policy, which can use realm- or principal-specific factors. For example, the expiration time MAY be set to the earliest of the following:

  • The expiration time (endtime) requested in the KRB_AS_REQ message.
  • The ticket's starttime plus the maximum allowable lifetime associated with the client principal from the authentication server's database.
  • The ticket's starttime plus the maximum allowable lifetime associated with the server principal.
  • The ticket's starttime plus the maximum lifetime set by the policy of the local realm.

If the requested expiration time minus the starttime (as worked out above) is less than a site-determined minimum lifetime, you get KDC_ERR_NEVER_VALID ๐Ÿ’€. If the requested expiration time for the ticket goes beyond what was determined above, and the 'RENEWABLE-OK' option was requested, then the RENEWABLE flag gets set in the new ticket, and the renew-till value is set as if the 'RENEWABLE' option had been requested. (The field and option names are fully described in Section 5.4.1 โœจ.)

If the RENEWABLE option was requested, or RENEWABLE-OK was set and a renewable ticket is being issued, then the renew-till field MAY be set to the earliest of:

  • Its requested value.
  • The starttime of the ticket plus the minimum of the two maximum renewable lifetimes associated with the principals' database entries.
  • The starttime of the ticket plus the maximum renewable lifetime set by the policy of the local realm.

The flags field of the new ticket gets these options set, if they were requested and the local realm's policy allows: FORWARDABLE, MAY-POSTDATE, POSTDATED, PROXIABLE, RENEWABLE. If the new ticket is postdated (the starttime is in the future), its INVALID flag gets set too ๐ŸŽ€

If all of the above succeeds, the server encrypts the ciphertext part of the ticket with the encryption key pulled from the server principal's record in the Kerberos database, using the encryption type associated with that principal's key. (This choice is NOT affected by the etype field in the request.) Then it formats a KRB_AS_REP message (see Section 5.4.2 ๐Ÿฆ‹), copies the addresses from the request into the caddr of the response, puts any required pre-authentication data into the padata of the response, and encrypts the ciphertext part with the client's key, using an acceptable encryption method requested in the etype field of the request, or some key specified by the pre-authentication mechanisms in use.

3.1.4. Generation of KRB_ERROR Message

Several errors can happen, and the Authentication Server responds by sending an error message, KRB_ERROR, back to the client, with the error-code and e-text fields set to appropriate values ๐Ÿšจ. The details of the error message contents are in Section 5.9.1 ๐Ÿ“–.

3.1.5. Receipt of KRB_AS_REP Message

If the reply message type is KRB_AS_REP, the client checks that the cname and crealm fields in the cleartext portion of the reply match what it asked for ๐Ÿ‘€. If any padata fields are present, they can be used to derive the right secret key for decrypting the message. The client decrypts the encrypted part of the response with its secret key, and checks that the nonce in there matches the nonce it sent in its request (this catches replays ๐Ÿ•ต๏ธโ€โ™€๏ธ). It also verifies that the sname and srealm in the response match the request (or are otherwise expected values), and that the host address field is correct too. Then it stores the ticket, session key, start and expiration times, and other info for later use ๐Ÿ’œ. The last-req field (and the deprecated key-expiration field) from the encrypted part of the response MAY be checked to warn the user that their key is about to expire. This lets the client program suggest remedial action, like a password change ๐Ÿ”‘

After validating the KRB_AS_REP message by checking the returned nonce against the one sent in the KRB_AS_REQ message, the client knows the current time on the KDC is whatever is in the authtime field of the encrypted part of the reply โฐ. The client can optionally use this value for clock synchronization in later messages, by recording with the ticket the difference (offset) between the authtime value and the local clock. That offset can then be used by the same user to adjust the time read from the system clock when generating messages [DGT96].

This technique MUST be used when adjusting for clock skew, instead of directly changing the system clock. The KDC reply is only authenticated to the user whose secret key was used, not to the system or workstation. If the clock were adjusted, an attacker colluding with a user logging into a workstation could agree on a password, and the resulting KDC reply would validate correctly even though it didn't come from a KDC the workstation trusts. This is serious business ๐Ÿ˜ฑ

Proper decryption of the KRB_AS_REP message is NOT enough for the host to verify the user's identity, though. The user and an attacker could team up to generate a KRB_AS_REP format message that decrypts properly but isn't from the real KDC. If the host wants to verify the user's identity, it MUST require the user to present application credentials that can be verified using a securely-stored secret key for the host. If those credentials check out, then the user's identity can be assured ๐Ÿซถ

3.1.6. Receipt of KRB_ERROR Message

If the reply message type is KRB_ERROR, the client treats it as an error and does whatever application-specific tasks are needed for recovery ๐Ÿ”ง


3.2. The Client/Server Authentication Exchange โœจ

Summary

   Message direction                         Message type    Section
   Client to Application server              KRB_AP_REQ      5.5.1
   [optional] Application server to client   KRB_AP_REP or   5.5.2
                                             KRB_ERROR       5.9.1

The client/server authentication (CS) exchange is how network applications authenticate the client to the server, and the server back to the client ๐Ÿ‘‘๐ŸŽ€. The client MUST have already acquired credentials for the server using the AS or TGS exchange ๐ŸŒˆ

3.2.1. The KRB_AP_REQ Message โœจ

okay so KRB_AP_REQ is the message that carries your auth info, and it SHOULD be part of the very first message in an authenticated transaction ๐Ÿ’… It bundles a ticket, an authenticator, and some extra bookkeeping (check Section 5.5.1 for the exact format ๐ŸŽ€). But the ticket on its own is NOT enough to authenticate a client, bestie ๐Ÿ˜ญ Tickets travel across the network in cleartext. (A ticket has an encrypted part and an unencrypted part, so "cleartext" means the whole unit, and anyone can copy it from one message and replay it in another without any real cryptography skills ๐Ÿ’€) That's where the authenticator comes in. It stops invalid replays of tickets by proving to the server that you know the session key for the ticket, so you're actually entitled to use it ๐Ÿ” Fun fact: KRB_AP_REQ is also called the 'authentication header' elsewhere ๐Ÿฆ‹

3.2.2. Generation of a KRB_AP_REQ Message ๐ŸŒธ

When a client wants to authenticate to a server, it gets a ticket and session key for the service it wants, either from a credentials cache, the AS exchange, or the TGS exchange ๐Ÿงš The client MAY re-use any tickets it holds until they expire ๐Ÿ” To use a ticket, the client builds a new Authenticator from the system time and its name. It can optionally add an application-specific checksum, an initial sequence number to be used in KRB_SAFE or KRB_PRIV messages, and/or a session subkey for negotiating a session key unique to this one session ๐Ÿซถ

Authenticators MUST NOT be re-used, and they SHOULD be rejected if replayed to a server ๐Ÿšซ Heads up, this can make apps on unreliable transports really tricky to code correctly ๐Ÿ˜ฉ If the transport might deliver duplicated messages, then either a new authenticator MUST be generated for each retry, or the application server MUST match requests and replies and replay the first reply whenever it spots a duplicate ๐Ÿ“ฌ

If a sequence number is included, it SHOULD be randomly chosen so that even after lots of messages it's not likely to collide with other sequence numbers in use ๐ŸŽฒ

The client MAY indicate that it requires mutual authentication, or the use of a session-key based ticket (for user-to-user authentication, see section 3.7 ๐Ÿค), by setting the appropriate flag(s) in the ap-options field of the message ๐Ÿณ๏ธ

The Authenticator is encrypted in the session key and combined with the ticket to form the KRB_AP_REQ message, which then gets sent to the end server along with any extra application-specific info ๐Ÿ’Œ


3.2.3. Receipt of KRB_AP_REQ Message ๐Ÿ‘€

Authentication is based on the server's current time of day (clocks MUST be loosely synchronized โฐ), the authenticator, and the ticket. Several errors are possible ๐Ÿ˜ฌ If something goes wrong, the server is expected to reply to the client with a KRB_ERROR message. That message MAY be wrapped inside the application protocol if its raw form isn't acceptable to the protocol ๐ŸŽ The format of error messages is described in Section 5.9.1.

Here's the algorithm for verifying auth info, it's basically a checklist โœ… If the message type is not KRB_AP_REQ, the server returns the KRB_AP_ERR_MSG_TYPE error. If the key version indicated by the Ticket in the KRB_AP_REQ isn't one the server can use (e.g., it points to an old key the server no longer has), the KRB_AP_ERR_BADKEYVER error is returned. If the USE-SESSION-KEY flag is set in the ap-options field, that tells the server user-to-user auth is in use, and the ticket is encrypted in the session key from the server's TGT rather than the server's secret key. See Section 3.7 for the full tea on how user-to-user authentication affects all messages in the Kerberos protocol ๐Ÿ’‹

Because a server can be registered in multiple realms with different keys in each, the srealm field in the unencrypted portion of the ticket in the KRB_AP_REQ is used to say which secret key the server should use to decrypt that ticket ๐Ÿ—๏ธ If the server doesn't have the proper key to decipher the ticket, the KRB_AP_ERR_NOKEY error code is returned ๐Ÿšช

The ticket is decrypted using the version of the server's key specified by the ticket. If the decryption routines detect a modification of the ticket (each encryption system MUST provide safeguards to detect modified ciphertext), the KRB_AP_ERR_BAD_INTEGRITY error is returned (chances are good that different keys were used to encrypt and decrypt) ๐Ÿšจ

The authenticator is decrypted using the session key extracted from the decrypted ticket. If decryption shows that it has been modified, the KRB_AP_ERR_BAD_INTEGRITY error is returned. The name and realm of the client from the ticket are compared against the same fields in the authenticator. If they don't match, the KRB_AP_ERR_BADMATCH error is returned, and normally that's caused by a client error or an attempted attack ๐Ÿ•ต๏ธ The addresses in the ticket (if any) are then searched for an address matching the operating-system reported address of the client. If no match is found, or the server insists on ticket addresses but none are present in the ticket, the KRB_AP_ERR_BADADDR error is returned. If the local (server) time and the client time in the authenticator differ by more than the allowable clock skew (e.g., 5 minutes), the KRB_AP_ERR_SKEW error is returned โณ

Unless the application server provides its own suitable means to protect against replay (for example, a challenge-response sequence initiated by the server after authentication, or use of a server-generated encryption subkey), the server MUST utilize a replay cache to remember any authenticator presented within the allowable clock skew. Careful analysis of the application protocol and implementation is recommended before eliminating this cache ๐Ÿง The replay cache stores at least the server name, along with the client name, time, and microsecond fields from the recently-seen authenticators. If a matching tuple is found, the KRB_AP_ERR_REPEAT error is returned. Note that the rejection here is restricted to authenticators from the same principal to the same server. Other client principals communicating with the same server should not have their authenticators rejected just because the time and microsecond fields happen to match some other client's authenticator ๐Ÿ™…

If a server loses track of authenticators presented within the allowable clock skew, it MUST reject all requests until the clock skew interval has passed. That gives assurance that any lost or replayed authenticators will fall outside the allowable clock skew and can no longer be successfully replayed โธ๏ธ If this were not done, an attacker could subvert the authentication by recording the ticket and authenticator sent over the network to a server, then replaying them following an event that caused the server to lose track of recently seen authenticators ๐Ÿ˜ฑ Dramatic, I know, but it's real.

Implementation note: If a client generates multiple requests to the KDC with the same timestamp, including the microsecond field, all but the first of the requests received will be rejected as replays. This might happen, for example, if the resolution of the client's clock is too coarse ๐Ÿ•ฐ๏ธ Client implementations SHOULD ensure that the timestamps are not reused, possibly by incrementing the microseconds field in the time stamp when the clock returns the same time for multiple requests โž•

If multiple servers (for example, different services on one machine, or a single service implemented on multiple machines) share a service principal (a practice we do not recommend in general, but that we acknowledge will be used in some cases), then either they MUST share this replay cache, or the application protocol MUST be designed so as to eliminate the need for it. Note that this applies to all of the services. If any of the application protocols does not have replay protection built in, an authenticator used with such a service could later be replayed to a different service with the same service principal but no replay protection, if the former doesn't record the authenticator information in the common replay cache ๐Ÿ•ต๏ธโ€โ™€๏ธ

If a sequence number is provided in the authenticator, the server saves it for later use in processing KRB_SAFE and/or KRB_PRIV messages. If a subkey is present, the server either saves it for later use or uses it to help generate its own choice for a subkey to be returned in a KRB_AP_REP message ๐Ÿ”‘

The server computes the age of the ticket: local (server) time minus the starttime inside the Ticket. If the starttime is later than the current time by more than the allowable clock skew, or if the INVALID flag is set in the ticket, the KRB_AP_ERR_TKT_NYV error is returned. Otherwise, if the current time is later than end time by more than the allowable clock skew, the KRB_AP_ERR_TKT_EXPIRED error is returned โŒ›

If all these checks succeed without an error, the server is assured that the client possesses the credentials of the principal named in the ticket, and thus that the client has been authenticated to the server ๐ŸŽ‰

Passing these checks provides only authentication of the named principal. It does not imply authorization to use the named service. Applications MUST make a separate authorization decision based upon the authenticated name of the user, the requested operation, local access control information such as that contained in a .k5login or .k5users file, and possibly a separate distributed authorization service ๐Ÿšง

3.2.4. Generation of a KRB_AP_REP Message ๐Ÿฆ‹

Typically, a client's request includes both the authentication information and its initial request in the same message, so the server doesn't need to explicitly reply to the KRB_AP_REQ ๐Ÿ“จ However, if mutual authentication (authenticating not only the client to the server, but also the server to the client ๐Ÿค) is being performed, the KRB_AP_REQ message will have MUTUAL-REQUIRED set in its ap-options field, and a KRB_AP_REP message is required in response. As with the error message, this message MAY be encapsulated in the application protocol if its "raw" form is not acceptable to the application's protocol ๐ŸŽ€ The timestamp and microsecond field used in the reply MUST be the client's timestamp and microsecond field (as provided in the authenticator) โฑ๏ธ If a sequence number is to be included, it SHOULD be randomly chosen as described above for the authenticator ๐ŸŽฒ A subkey MAY be included if the server desires to negotiate a different subkey ๐Ÿ—๏ธ The KRB_AP_REP message is encrypted in the session key extracted from the ticket ๐Ÿ”’

Note that in the Kerberos Version 4 protocol, the timestamp in the reply was the client's timestamp plus one. This is not necessary in Version 5, because Version 5 messages are formatted in such a way that it is not possible to create the reply by judicious message surgery (even in encrypted form) without knowledge of the appropriate encryption keys ๐Ÿง 

3.2.5. Receipt of KRB_AP_REP Message โœจ

okay so if a KRB_AP_REP message comes back, the client grabs the session key from the credentials it got for the server and uses it to decrypt the message ๐Ÿ”. Then it checks that the timestamp and microsecond fields match the ones in the Authenticator it sent over. If they match, the client knows the server is legit ๐Ÿซถ. The sequence number and subkey (if there is one) get saved for later ๐Ÿ’พ. (Heads up: when encrypting the KRB_AP_REP message, the sub-session key is NOT used, even if one shows up in the Authenticator ๐Ÿ™…โ€โ™€๏ธ.)

3.2.6. Using the Encryption Key

once the KRB_AP_REQ/KRB_AP_REP exchange is done, the client and server share an encryption key the application can use ๐Ÿ—๏ธ. Sometimes using that session key is just built into the protocol, and other times you have to pick a method from a few options ๐Ÿค”. The application MAY choose the actual encryption key for KRB_PRIV, KRB_SAFE, or other application-specific uses, based on the session key from the ticket and the subkeys in the KRB_AP_REP message and the authenticator ๐Ÿ’…. Implementations of the protocol MAY provide routines to pick subkeys from session keys and random numbers, and to generate a negotiated key to send back in the KRB_AP_REP message โœจ.

To protect against random number generation failing on the client, it is strongly encouraged that any key an application derives for later use includes the full key entropy from the KDC-generated session key in the ticket ๐ŸŽฒ. How to use the key (like choosing an encryption or checksum type) is left up to the application programmer ๐Ÿง‘โ€๐Ÿ’ป. Kerberos doesn't restrict your implementation options, but here's one way it could be done ๐ŸŒธ.

One way an application can negotiate a key for later integrity and privacy protection: the client proposes a key in the subkey field of the authenticator ๐Ÿฆ‹. The server then picks a key using the client's proposed key as input, and sends the new subkey back in the subkey field of the application reply ๐Ÿ’Œ. That key can then be used for the rest of the communication ๐ŸŽ€.

With both one-way and mutual authentication exchanges, the peers should be careful not to send sensitive info to each other without proper assurances ๐Ÿ™ˆ. Especially, applications that need privacy or integrity SHOULD use the KRB_AP_REP response from the server to the client, so both sides can confirm who the other one is ๐Ÿ‘‘. If an application protocol needs its messages to be private, it can use the KRB_PRIV message (section 3.5) ๐Ÿ”’. The KRB_SAFE message (Section 3.4) can be used to make sure nothing got messed with ๐Ÿ›ก๏ธ.


3.3. The Ticket-Granting Service (TGS) Exchange

Summary

         Message direction       Message type     Section
         1. Client to Kerberos   KRB_TGS_REQ      5.4.1
         2. Kerberos to client   KRB_TGS_REP or   5.4.2
                                 KRB_ERROR        5.9.1

okay so the TGS exchange is the convo between a client and the Kerberos TGS ๐ŸŽŸ๏ธ. A client starts it when it wants credentials for a given server (which might be registered in a remote realm), when it wants to renew or validate an existing ticket, or when it wants a proxy ticket ๐Ÿงš. In the first case, the client already needs a ticket for the Ticket-Granting Service from the AS exchange (the TGT usually shows up when a client first authenticates, like when a user logs in) ๐Ÿ”‘. The TGS message format is almost identical to the AS exchange, and the big difference is that encryption and decryption here do NOT happen under the client's key ๐Ÿ˜ฎ. Instead, it uses the session key from the TGT or renewable ticket, or the sub-session key from an Authenticator ๐Ÿ—๏ธ. Just like every application server, the TGS won't accept expired tickets, so once a renewable or TGT expires, the client has to run a separate exchange to get valid ones โฐ.

The TGS exchange has two messages: a request (KRB_TGS_REQ) from the client to the Kerberos Ticket-Granting Server, and a reply (KRB_TGS_REP or KRB_ERROR) ๐Ÿ“จ. The KRB_TGS_REQ message has info that authenticates the client plus a request for credentials ๐Ÿชช. The authentication info is the authentication header (KRB_AP_REQ), which includes the client's previously obtained ticket-granting, renewable, or invalid ticket ๐ŸŽซ. In the TGT and proxy cases, the request MAY include one or more of these: a list of network addresses, a collection of typed authorization data to be sealed in the ticket for the application server to use, or additional tickets (more on those later) ๐ŸŒˆ. The TGS reply (KRB_TGS_REP) has the requested credentials, encrypted in the session key from the TGT or renewable ticket, or, if there is one, in the sub-session key from the Authenticator (part of the authentication header) ๐Ÿ’Œ. The KRB_ERROR message has an error code and text explaining what went wrong, and it is NOT encrypted ๐Ÿ™ƒ. The KRB_TGS_REP message has info that can be used to detect replays and to match it to the message it replies to ๐Ÿ”. The KRB_ERROR message also has info that can be used to match it to the message it replies to ๐Ÿงฉ. The same comments about integrity protection of KRB_ERROR messages from Section 3.1 apply to the TGS exchange too ๐Ÿ’….

3.3.1. Generation of KRB_TGS_REQ Message

Before sending a request to the ticket-granting service, the client MUST figure out which realm the application server is believed to be registered in ๐Ÿ—บ๏ธ. There are a few ways to do this. It might already be known beforehand (since the realm is part of the principal identifier), it might be stored in a nameserver, or it might come from a configuration file ๐Ÿ“‚. If the realm comes from a nameserver, watch out: there's a danger of being spoofed if the nameservice giving out the realm name isn't authenticated ๐Ÿ˜ฑ. That could lead to using a realm that's been compromised, which would let an attacker mess with the application server's authentication to the client ๐Ÿ’€.

If the client knows the service principal name and realm and doesn't already have a TGT for the right realm, then it has to get one ๐ŸŽซ. It tries first by asking a Kerberos server it already has a TGT for, for a TGT to the destination realm (using the KRB_TGS_REQ message, recursively) ๐Ÿ”. The Kerberos server MAY return a TGT for the desired realm, and then you're good to go โœจ. Or, the Kerberos server MAY return a TGT for a realm that's "closer" to the desired one (further along the standard hierarchical path between the client's realm and the requested server's realm) ๐Ÿ›ค๏ธ. Heads up: if the Kerberos servers are misconfigured, the authentication path could loop, so the client should be careful to catch and avoid that ๐Ÿ™ˆ.

If the Kerberos server gives back a TGT for a realm that's "closer" than the desired one, the client MAY use local policy configuration to check that the authentication path is acceptable ๐Ÿง. Or, a client MAY choose its own authentication path instead of relying on the Kerberos server to pick one ๐Ÿ—บ๏ธ. Either way, any policy or configuration info used to choose or validate authentication paths (whether it came from the Kerberos server or the client) MUST come from a trusted source ๐Ÿ”’.

When a client gets a TGT that's "closer" to the destination realm, it MAY cache that ticket and reuse it in future KRB-TGS exchanges with services in the "closer" realm ๐Ÿ’พ. But, if the client got a TGT for the "closer" realm by starting at the initial KDC instead of as part of getting another ticket, a shorter path to the "closer" realm might be used ๐Ÿ›ฃ๏ธ. That shorter path can be nicer because fewer intermediate KDCs would know the session key of the ticket involved ๐Ÿคซ. So for this reason, clients SHOULD check whether they trust the realms that were transited to get the "closer" ticket before deciding to use it later ๐Ÿง .

Once the client has a TGT for the right realm, it figures out which Kerberos servers serve that realm and contacts one of them ๐Ÿ“ž. The list might come from a configuration file or network service, or it MAY be generated from the realm name ๐Ÿ“‹. As long as the secret keys exchanged between realms stay secret, using a false Kerberos server only causes denial of service ๐Ÿšซ.

Just like in the AS exchange, the client MAY set a bunch of options in the KRB_TGS_REQ message ๐ŸŽ›๏ธ. One option is ENC-TKT-IN-SKEY, which is used for user-to-user authentication. You can find an overview of user-to-user authentication in Section 3.7 ๐Ÿ“–. When the client generates the KRB_TGS_REQ message with this option, it means the client is including a TGT obtained from the application server in the additional tickets field of the request, and the KDC SHOULD encrypt the ticket for the application server using the session key from this additional ticket, instead of a server key from the principal database ๐Ÿซง.

The client prepares the KRB_TGS_REQ message, putting an authentication header in the padata field as an element, and including the same fields as in the KRB_AS_REQ message plus a few optional ones: the enc-authorizatfion-data field for application server use, and additional tickets required by some options ๐ŸŽ€.

When preparing the authentication header, the client can pick a sub-session key that the Kerberos server's response will be encrypted under ๐Ÿ”. If the client does pick one, it has to make sure the sub-session key is random ๐ŸŽฒ.

If no sub-session key is specified, the session key from the TGT will be used ๐Ÿ—๏ธ. If enc-authorization-data is present, it MUST be encrypted in the sub-session key from the authenticator portion of the authentication header (if present), or, if there isn't one, by using the session key from the TGT ๐Ÿ’–.

Once it's all prepared, the message gets sent to a Kerberos server for the destination realm ๐Ÿš€.

3.3.2. Receipt of KRB_TGS_REQ Message

okay so the KRB_TGS_REQ message gets processed kinda like KRB_AS_REQ ๐Ÿ’…, but there are WAY more checks to do ๐Ÿ˜ญ. First, the Kerberos server MUST figure out which server the accompanying ticket is for, and it MUST pick the right key to decrypt it ๐Ÿ”‘. For a normal KRB_TGS_REQ, the ticket is for the ticket-granting service, so the TGS's key gets used. If the TGT was issued by another realm, then the appropriate inter-realm key MUST be used ๐ŸŒ. If (a) the accompanying ticket is not a TGT for the current realm, but it is for an application server in the current realm, (b) the RENEW, VALIDATE, or PROXY options are specified in the request, and (c) the server being asked for a ticket is the server named in that accompanying ticket, then the KDC decrypts the ticket in the authentication header using the key of the server it was issued for. If no ticket can be found in the padata field, the KDC_ERR_PADATA_TYPE_NOSUPP error is returned ๐Ÿ™ˆ.

Once the accompanying ticket is decrypted, the user-supplied checksum in the Authenticator MUST be verified against the contents of the request, and the message MUST be rejected if the checksums don't match (with an error code of KRB_AP_ERR_MODIFIED) or if the checksum isn't collision-proof (with an error code of KRB_AP_ERR_INAPP_CKSUM) ๐Ÿšซ. If the checksum type isn't supported, the KDC_ERR_SUMTYPE_NOSUPP error is returned. If the authorization-data are present, they get decrypted using the sub-session key from the Authenticator ๐Ÿ”“.

If any of the decryptions show failed integrity checks, the KRB_AP_ERR_BAD_INTEGRITY error is returned ๐Ÿ’€.

As discussed in Section 3.1.2, the KDC MUST send a valid KRB_TGS_REP message if it gets a KRB_TGS_REQ message that's identical to one it has recently processed โœจ. However, if the authenticator is a replay but the rest of the request isn't identical, then the KDC SHOULD return KRB_AP_ERR_REPEAT ๐Ÿ”.

3.3.3. Generation of KRB_TGS_REP Message

the KRB_TGS_REP message shares its format with the KRB_AS_REP (KRB_KDC_REP), it's just that its type field is set to KRB_TGS_REP ๐ŸŽ€. The detailed spec lives in Section 5.4.2 ๐Ÿ“–.

The response includes a ticket for the requested server, or for a ticket granting server of an intermediate KDC that the client needs to contact to get the requested ticket ๐Ÿฆ‹. The Kerberos database gets queried to pull up the record for the right server (including the key the ticket will be encrypted with) ๐Ÿ—‚๏ธ. If the request is for a TGT for a remote realm, and no key is shared with that requested realm, then the Kerberos server selects the realm 'closest' to the requested realm that it does share a key with, and uses that realm instead ๐ŸŒธ. This is the only case where the KDC's response is for a different server than the one the client asked for, so it's kind of a big deal ๐Ÿ‘€.

By default, the address field, the client's name and realm, the list of transited realms, the time of initial authentication, the expiration time, and the authorization data of the newly-issued ticket all get copied from the TGT or renewable ticket ๐Ÿ’œ. If the transited field needs updating but the transited type isn't supported, the KDC_ERR_TRTYPE_NOSUPP error is returned.

If the request specifies an endtime, then the endtime of the new ticket is set to the minimum of (a) that request, (b) the endtime from the TGT, and (c) the starttime of the TGT plus the minimum of the maximum life for the application server and the maximum life for the local realm. (The maximum life for the requesting principal was already applied when the TGT was issued, so we don't redo that one ๐Ÿ™ƒ.) If the new ticket is going to be a renewal, then the endtime above gets replaced by the minimum of (a) the value of the renew_till field of the ticket and (b) the starttime for the new ticket plus the life (endtime-starttime) of the old ticket โณ.

If the FORWARDED option was requested, the resulting ticket will contain the addresses the client specified ๐Ÿงš. This option only gets honored if the FORWARDABLE flag is set in the TGT. The PROXY option is similar: the resulting ticket will contain the addresses the client specified, but it only gets honored if the PROXIABLE flag in the TGT is set. The PROXY option will NOT be honored on requests for additional TGTs ๐Ÿ™…โ€โ™€๏ธ.

If the requested starttime is absent, points to a time in the past, or is within the window of acceptable clock skew for the KDC and the POSTDATE option hasn't been specified, then the starttime of the ticket is set to the authentication server's current time โฐ. If it points to a time in the future beyond the acceptable clock skew, but the POSTDATED option hasn't been specified or the MAY-POSTDATE flag isn't set in the TGT, then the error KDC_ERR_CANNOT_POSTDATE is returned ๐Ÿ˜ค. Otherwise, if the TGT has the MAY-POSTDATE flag set, the resulting ticket gets postdated, and the requested starttime is checked against the policy of the local realm. If that's acceptable, the ticket's starttime is set as requested and the INVALID flag is set ๐ŸŒ™. The postdated ticket MUST be validated before use by presenting it to the KDC after the starttime has been reached ๐Ÿ•ฐ๏ธ. And no matter what, the starttime, endtime, or renew-till time of a newly-issued postdated ticket can NEVER extend beyond the renew-till time of the TGT ๐Ÿšง.

If the ENC-TKT-IN-SKEY option has been specified and an additional ticket has been included in the request, it means the client is using user-to-user authentication to prove its identity to a server that doesn't have access to a persistent key ๐Ÿค. Section 3.7 describes the effect of this option on the entire Kerberos protocol. When generating the KRB_TGS_REP message, this option in the KRB_TGS_REQ message tells the KDC to decrypt the additional ticket using the key for the server it was issued to, and to verify that it's a TGT ๐Ÿ”. If the name of the requested server is missing from the request, the name of the client in the additional ticket gets used. Otherwise, the name of the requested server gets compared to the name of the client in the additional ticket. If they're different, the request gets rejected ๐Ÿ™…. If the request succeeds, the session key from the additional ticket is used to encrypt the new ticket that gets issued, instead of using the key of the server the new ticket is for ๐Ÿ’–.

If (a) the name of the server in the ticket presented to the KDC as part of the authentication header is NOT that of the TGS itself, (b) the server is registered in the realm of the KDC, and (c) the RENEW option is requested, then the KDC verifies that the RENEWABLE flag is set in the ticket, that the INVALID flag is NOT set, and that the renew_till time is still in the future ๐Ÿ”„. If the VALIDATE option is requested, the KDC checks that the starttime has passed and that the INVALID flag is set โœ…. If the PROXY option is requested, the KDC checks that the PROXIABLE flag is set in the ticket ๐Ÿช„. If the tests succeed and the ticket passes the hot-list check described in the next section, the KDC issues the appropriate new ticket ๐ŸŽ‰.

The ciphertext part of the response in the KRB_TGS_REP message is encrypted in the sub-session key from the Authenticator if one is present, or in the session key from the TGT ๐Ÿ—๏ธ. It is NOT encrypted using the client's secret key ๐Ÿ™ˆ. Also, the client's key's expiration date and the key version number fields are left out, since those values are stored with the client's database record, and that record isn't needed to satisfy a request based on a TGT ๐Ÿ“ญ.

3.3.3.1. Checking for Revoked Tickets

Whenever a request is made to the ticket-granting server, the presented ticket(s) get checked against a hot-list of tickets that have been canceled ๐Ÿšจ. This hot-list might be implemented by storing a range of issue timestamps for 'suspect tickets'; if a presented ticket had an authtime in that range, it gets rejected ๐Ÿ›‘. This way, a stolen TGT or renewable ticket can't be used to get additional tickets (renewals or otherwise) once the theft has been reported to the KDC for the realm the server lives in ๐Ÿ•ต๏ธโ€โ™€๏ธ. Any normal ticket obtained before it was reported stolen will still be valid (because tickets don't need any interaction with the KDC), but only until its normal expiration time โณ. If TGTs have been issued for cross-realm authentication, using that cross-realm TGT won't be affected unless the hot-list gets propagated to the KDCs for the realms those cross-realm tickets were issued for ๐ŸŒˆ.

3.3.3.2. Encoding the Transited Field โœจ

okay so if the server in the TGT that the client shows the KDC (as part of the authentication header) is the ticket-granting service, but that TGT was issued from a different realm, the KDC goes and grabs the inter-realm key it shares with that realm ๐Ÿ”‘ and uses it to decrypt the ticket. if the ticket checks out, the KDC honors the request, subject to the constraints outlined above in the section describing the AS exchange ๐Ÿ’…. the realm part of the client's identity gets taken from the TGT.

now here's the fun part ๐Ÿงš. the name of the realm that issued the TGT gets added to the transited field of the new ticket, but only if it's not the realm of the client principal. how that works: read the transited field from the TGT (it's treated as an unordered set of realm names ๐Ÿซง), toss the new realm into the set, then build and write out its encoded (shorthand) form. that last step might shuffle the existing encoding around a bit.

ngl this next bit is so iconic ๐Ÿ‘‘. the ticket-granting service does not add its own realm name. its job is to add the previous realm. why? it stops a sketchy Kerberos server from just leaving out its own name on purpose ๐Ÿ™ˆ. (it could still leave out other realms' names though, so yeah, not perfect.)

the names of the local realm and the principal's realm are NOT supposed to go in the transited field. they're already listed elsewhere in the ticket, and both are known to have been part of authenticating the principal, so it's giving redundancy ๐Ÿ’€. because endpoints get skipped, both local and single-hop inter-realm auth end up with a transited field that's empty ๐ŸŒธ.

because every transited realm gets added, this field could get really long ๐Ÿ˜ญ. so its contents are encoded to keep it short. the first encoding was built for the super normal case of inter-realm communication: a hierarchical setup of realms using either domain or X.500 style realm names ๐ŸŒˆ. it's called DOMAIN-X500-COMPRESS, and here's how it works.

realm names in the transited field are separated by a ",". the ",", "\", trailing "."s, and leading spaces (" ") are special characters. if any of them is part of a realm name, they MUST be quoted in the transited field by putting a "\" in front of them ๐ŸŽ€.

a realm name ending with a "." gets read as being prepended to the previous realm. so traversing EDU, MIT.EDU, ATHENA.MIT.EDU, WASHINGTON.EDU, and CS.WASHINGTON.EDU looks like this:

"EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.".

if ATHENA.MIT.EDU or CS.WASHINGTON.EDU were endpoints, they wouldn't show up in the field, so you'd get:

"EDU,MIT.,WASHINGTON.EDU"

a realm name beginning with a "/" gets read as being appended to the previous realm. for appending purposes, the realm before the first listed realm counts as the null realm (""). if a "/"-starting realm name is going to stand by itself, then it SHOULD be preceded by a space (" "). traversing /COM/HP/APOLLO, /COM/HP, /COM, and /COM/DEC looks like this:

"/COM,/HP,/APOLLO, /COM/DEC".

same deal as before: if /COM/HP/APOLLO and /COM/DEC were endpoints, they'd get left out, and you'd have:

"/COM,/HP"
a null subfield sitting next to a "," means every realm between the previous realm and the next one got traversed ๐Ÿง . for null subfield purposes, the client's realm counts as coming before everything in the field, and the server's realm counts as coming after. so "," on its own means all realms on the path between client and server were traversed. ",EDU, /COM," means every realm from the client's realm up to EDU (domain style hierarchy) was traversed, AND everything from /COM down to the server's realm (X.500 style) was traversed too. this could happen if the EDU realm in one hierarchy shares an inter-realm key directly with the /COM realm in another hierarchy ๐Ÿคฏ.

3.3.4. Receipt of KRB_TGS_REP Message ๐ŸŽ

when the client gets the KRB_TGS_REP, it's processed the same way as the KRB_AS_REP processing we went over earlier ๐Ÿ”. the main difference is that the ciphertext part of the response has to be decrypted using the sub-session key from the Authenticator (if one was specified in the request) or the session key from the TGT, NOT the client's secret key. the server name in the reply is the true principal name of the service ๐Ÿซถ.


3.4. The KRB_SAFE Exchange ๐Ÿ›ก๏ธ

the KRB_SAFE message MAY be used by clients who need to detect modifications to the messages they exchange ๐Ÿ‘€. how it does that: it includes a keyed collision-proof checksum of the user data plus some control information. the checksum is keyed with an encryption key (usually the last key negotiated via subkeys, or the session key if no negotiation happened) ๐Ÿ”.

3.4.1. Generation of a KRB_SAFE Message ๐Ÿ’Œ

when an application wants to send a KRB_SAFE message, it collects its data and the right control information, then computes a checksum over all of it. the checksum algorithm should be the keyed checksum that's mandated to be implemented alongside the crypto system used for the sub-session or session key. the checksum gets generated with the sub-session key if one's present, or with the session key. some implementations use a different checksum algorithm for KRB_SAFE messages, but doing that in an interoperable way isn't always possible ๐Ÿ™ƒ.

the control information for a KRB_SAFE message includes both a timestamp and a sequence number. the designer of an application that uses KRB_SAFE MUST choose at least one of the two mechanisms, and that choice SHOULD be based on what the application protocol actually needs ๐ŸŽฏ.

sequence numbers are useful when all the messages sent will be received by one's peer. connection state is already required to keep the session key, so keeping track of the next sequence number shouldn't be an extra headache ๐Ÿ’….

if the application protocol is expected to tolerate lost messages without them being resent, then the timestamp is the right replay detection mechanism. timestamps are also the right call for multi-cast protocols where all of one's peers share a common sub-session key, but some messages only go to a subset of those peers ๐Ÿ“ก.

after computing the checksum, the client transmits the information and checksum to the recipient in the message format specified in Section 5.6.1 ๐Ÿ“ฆ.

3.4.2. Receipt of KRB_SAFE Message ๐Ÿ”

when an application receives a KRB_SAFE message, it verifies it like this. if any error happens, an error code gets reported for the application to use ๐Ÿšจ.

first, the message gets checked by verifying that the protocol version and type fields match the current version and KRB_SAFE, respectively. a mismatch generates a KRB_AP_ERR_BADVERSION or KRB_AP_ERR_MSG_TYPE error ๐Ÿ˜ฌ. next, the application verifies that the checksum used is a collision-proof keyed checksum that uses keys compatible with the sub-session or session key (or with the application key derived from the session or sub-session keys). if it isn't, a KRB_AP_ERR_INAPP_CKSUM error is generated.

the sender's address MUST be included in the control information. the recipient checks that the operating system's report of the sender's address matches the sender's address in the message. and if a recipient address is specified (or the recipient requires one), one of the recipient's addresses has to show up as the recipient's address in the message ๐Ÿ . to play nice with network address translation, senders MAY use the directional address type specified in Section 8.1 for the sender address and leave out recipient addresses ๐ŸŒ. a failed match in either case generates a KRB_AP_ERR_BADADDR error.

then the timestamp and usec and/or the sequence number fields get checked. if timestamp and usec are expected but not present, or they're present but not current, the KRB_AP_ERR_SKEW error is generated โฐ. timestamps don't have to be strictly ordered; they only have to be in the skew window. if the server name, along with the client name, time, and microsecond fields from the Authenticator match any recently-seen (sent or received) tuple, the KRB_AP_ERR_REPEAT error is generated ๐Ÿ”. if an incorrect sequence number is included, or a sequence number is expected but missing, the KRB_AP_ERR_BADORDER error is generated. and if neither a timestamp and usec nor a sequence number is present, a KRB_AP_ERR_MODIFIED error is generated ๐Ÿ˜ฑ.

finally, the checksum is computed over the data and control information. if it doesn't match the received checksum, a KRB_AP_ERR_MODIFIED error is generated ๐Ÿ’ฅ.

if all the checks succeed, the application can be sure the message came from its peer and wasn't modified in transit ๐Ÿซถโœจ.

implementations SHOULD accept any checksum algorithm they implement that has both adequate security and keys compatible with the sub-session or session key. unkeyed or non-collision-proof checksums are NOT suitable for this use ๐Ÿ™…โ€โ™€๏ธ.


3.5. The KRB_PRIV Exchange ๐Ÿ”’

the KRB_PRIV message MAY be used by clients who need confidentiality AND the ability to detect modifications to exchanged messages ๐Ÿคซ. it does this by encrypting the messages and adding control information.

3.5.1. Generation of a KRB_PRIV Message ๐Ÿ—๏ธ

when an application wants to send a KRB_PRIV message, it collects its data and the appropriate control information (specified in Section 5.7.1), then encrypts all of it under an encryption key (usually the last key negotiated via subkeys, or the session key if no negotiation has occurred) ๐Ÿ’–. as part of the control information, the client MUST choose to use a timestamp or a sequence number (or both). see the discussion in Section 3.4.1 for guidelines on which to pick ๐ŸŽ€. after the user data and control information are encrypted, the client sends the ciphertext and some "envelope" information to the recipient ๐Ÿ“ฌ.

3.5.2. Receipt of KRB_PRIV Message

okay so when an app gets a KRB_PRIV message ๐Ÿ’Œ, it has to check it before trusting anything. If something goes wrong, an error code gets reported so the app can handle it ๐Ÿซถ.

First, the protocol version and type fields get checked to make sure they match the current version and KRB_PRIV. If they don't, you get KRB_AP_ERR_BADVERSION or KRB_AP_ERR_MSG_TYPE ๐Ÿ˜ญ. Then the app decrypts the ciphertext and processes the plaintext. If decryption shows the data was modified, that's a KRB_AP_ERR_BAD_INTEGRITY error ๐Ÿ’€.

Next up are addresses ๐Ÿก. The sender's address MUST be included in the control information, and the recipient checks that the operating system's report of the sender's address matches the sender's address in the message. If a recipient address is specified or the recipient requires an address, then one of the recipient's addresses MUST also appear as the recipient's address in the message. Where a sender's or receiver's address might not otherwise match the address in a message because of network address translation, an application MAY be written to use addresses of the directional address type in place of the actual network address ๐Ÿงš.

If either case fails to match, you get a KRB_AP_ERR_BADADDR error ๐Ÿ™ˆ. To work with network address translation, implementations MAY use the directional address type defined in Section 7.1 for the sender address and include no recipient address ๐ŸŒธ.

Then the timestamp and usec and/or the sequence number fields get checked โฐ. If timestamp and usec are expected and not present, or if they're present but not current, the KRB_AP_ERR_SKEW error is generated. If the server name, along with the client name, time, and microsecond fields from the Authenticator match any such recently-seen tuples, the KRB_AP_ERR_REPEAT error is generated. If an incorrect sequence number is included, or if a sequence number is expected but not present, the KRB_AP_ERR_BADORDER error is generated. If neither a timestamp and usec nor a sequence number is present, a KRB_AP_ERR_MODIFIED error is generated ๐Ÿ˜ค.

If all the checks pass, the application can assume the message was generated by its peer and was securely transmitted, with no intruders peeking at the unencrypted contents ๐Ÿ”ฅโœจ.


3.6. The KRB_CRED Exchange

the KRB_CRED message MAY be used by clients who need to send Kerberos credentials from one host to another ๐Ÿ“จ. It does this by sending the tickets together with encrypted data that holds the session keys and other info about those tickets ๐Ÿ”.

3.6.1. Generation of a KRB_CRED Message

when an app wants to send a KRB_CRED message, it first gets credentials to send to the remote host using the KRB_TGS exchange ๐ŸŽŸ๏ธ. Then it builds the KRB_CRED message using the ticket or tickets it got, and puts the session key needed to use each ticket in the key field of the matching KrbCredInfo sequence in the encrypted part of the KRB_CRED message ๐Ÿ—๏ธ.

Other info about each ticket, the stuff obtained during the KRB_TGS exchange, also goes into that same KrbCredInfo sequence in the encrypted part ๐Ÿ“ฆ. The current time goes in too, and if the application specifically needs them, the nonce, s-address, and r-address fields go in as well. Then the whole encrypted part gets encrypted under an encryption key that was previously exchanged in the KRB_AP exchange (usually the last key negotiated via subkeys, or the session key if no negotiation happened) ๐Ÿ’œ.

Implementation note: When building a KRB_CRED message for a GSSAPI initial context token, the MIT implementation of Kerberos won't encrypt the KRB_CRED message if the session key is a DES or triple DES key ๐Ÿ˜ฌ. For interop with MIT, the Microsoft implementation won't encrypt the KRB_CRED in a GSSAPI token if it's using a DES session key. Starting at version 1.2.5, MIT Kerberos can receive and decode either encrypted or unencrypted KRB_CRED tokens in the GSSAPI exchange ๐Ÿ™Œ. The Heimdal implementation of Kerberos can also accept either encrypted or unencrypted KRB_CRED messages. Since the KRB_CRED message in a GSSAPI token is encrypted in the authenticator, the MIT behavior doesn't present a security problem, although it is a violation of the Kerberos specification ๐Ÿค“.

3.6.2. Receipt of KRB_CRED Message

when an app receives a KRB_CRED message, it verifies it, and if anything goes wrong, an error code gets reported for the app to use ๐Ÿ•ต๏ธโ€โ™€๏ธ. The message is verified by checking that the protocol version and type fields match the current version and KRB_CRED. If they don't, you get KRB_AP_ERR_BADVERSION or KRB_AP_ERR_MSG_TYPE ๐Ÿ˜ญ. Then the app decrypts the ciphertext and processes the plaintext. If decryption shows the data was modified, a KRB_AP_ERR_BAD_INTEGRITY error is generated ๐Ÿ’€.

If present or required, the recipient MAY verify that the operating system's report of the sender's address matches the sender's address in the message, and that one of the recipient's addresses appears as the recipient's address in the message. Honestly, the address check doesn't add any real security ๐Ÿ™ƒ. The address, if present, was already checked in the KRB_AP_REQ message, and there's no benefit for an attacker in reflecting a KRB_CRED message back to its originator. So the recipient MAY ignore the address even if it's present, which helps out in Network Address Translation (NAT) environments ๐ŸŒ. If either case fails to match, you get a KRB_AP_ERR_BADADDR error. Recipients MAY skip the address check, since the KRB_CRED message generally can't be reflected back to the originator ๐Ÿฆ‹. Next, the timestamp and usec fields (and the nonce field, if required) get checked โฑ๏ธ. If the timestamp and usec aren't present, or they're present but not current, the KRB_AP_ERR_SKEW error is generated.

If all the checks pass, the application stores each of the new tickets in its credentials cache, together with the session key and other info from the matching KrbCredInfo sequence in the encrypted part of the KRB_CRED message ๐ŸŽ€โœจ.


3.7. User-to-User Authentication Exchanges

user-to-user authentication gives you a way to authenticate when the verifier doesn't have access to a long-term service key ๐Ÿ”‘. This might happen when a server (like a window server) is running as a user on a workstation. In that case the server may have the TGT that the user got when they logged in to the workstation, but since the server runs as an unprivileged user, it might not have access to system keys ๐Ÿ˜ฉ. Similar situations can come up when running peer-to-peer applications ๐ŸŒˆ.

Summary

       Message direction                    Message type     Sections
       0. Message from application server   Not specified
       1. Client to Kerberos                KRB_TGS_REQ      3.3 & 5.4.1
       2. Kerberos to client                KRB_TGS_REP or   3.3 & 5.4.2
                                            KRB_ERROR        5.9.1
       3. Client to application server      KRB_AP_REQ       3.2 & 5.5.1

so to deal with this, the Kerberos protocol lets the client ask that the ticket issued by the KDC be encrypted using a session key from a TGT issued to the party that will verify the authentication ๐Ÿช„. That TGT has to be obtained from the verifier through an exchange outside the Kerberos protocol, usually as part of the application protocol. This message shows up in the summary above as message 0 ๐Ÿ“ฌ. Note that because the TGT is encrypted in the KDC's secret key, it can't be used for authentication without the corresponding secret key ๐Ÿ”’. And since the verifier doesn't reveal its corresponding secret key, handing over a copy of the verifier's TGT doesn't let anyone impersonate the verifier ๐Ÿ™…โ€โ™€๏ธ.

Message 0 in the table above is an application-specific negotiation between the client and server ๐Ÿค. At the end of it, both sides have decided they'll use user-to-user authentication, and the client has obtained the server's TGT ๐Ÿ’–.

Next, the client includes the server's TGT as an additional ticket in its KRB_TGS_REQ request to the KDC (message 1 in the table above) and specifies the ENC-TKT-IN-SKEY option in that request ๐ŸŽฏ.

If it's validated according to the instructions in Section 3.3.3, the application ticket returned to the client (message 2 in the table above) will be encrypted using the session key from the additional ticket, and the client will note this when it uses or stores the application ticket ๐Ÿ“.

When the client contacts the server using a ticket obtained for user-to-user authentication (message 3 in the table above), the client MUST specify the USE-SESSION-KEY flag in the ap-options field ๐Ÿšฉ. This tells the application server to use the session key associated with its TGT to decrypt the server ticket provided in the application request ๐Ÿ‘‘.

4. Encryption and Checksum Specifications โœจ

Okay bestie, so the Kerberos protocols in this document are built to encrypt messages of any size, using stream or block ciphers ๐Ÿ”. Encryption is how everyone proves who they are. Every realm's Key Distribution Center is trusted by all the principals registered in that realm to keep a secret key safe ๐Ÿซถ. If you can prove you know that secret key, that's how the Kerberos system checks you're really you ๐Ÿ’….

The KDC uses the principal's secret key (in the AS exchange) or a shared session key (in the TGS exchange) to encrypt its responses to ticket requests. Being able to get the secret key or session key means you know the right keys, and that proves who the KDC is ๐Ÿ‘‘. A principal can decrypt the KDC response and then show a Ticket and a properly formed Authenticator (made with the session key from that response) to a service, and that proves the principal's identity. It goes the other way too: the service can pull the session key out of the Ticket and prove it knows it, and that proves the service's identity ๐Ÿฆ‹.

[RFC3961] defines a framework for making encryption and checksum mechanisms for Kerberos. It also defines several of those mechanisms, and more might get added in future updates to that document ๐ŸŒˆ.

The string-to-key operation from [RFC3961] is used to make a long-term key for a principal (usually a user) ๐Ÿ”‘. If no salt string is given through pre-authentication data, the default salt is the realm and name components of the principal, joined in order with no separators ๐Ÿ“. Unless it's stated otherwise, the default string-to-key opaque parameter set defined in [RFC3961] is used โœจ.

Encrypted data, keys, and checksums are sent using the EncryptedData, EncryptionKey, and Checksum data objects from Section 5.2.9 ๐Ÿ’–. The encryption, decryption, and checksum operations in this document use the matching encryption, decryption, and get_mic operations from [RFC3961]. Each one implicitly makes a "specific key" using the "key usage" value given in the description of that EncryptedData or Checksum object, so every operation gets its own key ๐Ÿงš. Heads up, in some cases the value you use depends on how the key was picked or on the context of the message ๐Ÿ‘€.

Key usages are unsigned 32-bit integers, and zero is not allowed ๐Ÿ™…โ€โ™€๏ธ. The key usage values for encrypting or checksumming Kerberos messages are listed in Section 5 with the message definitions. Key usage values 512-1023 are reserved for uses inside a Kerberos implementation (like seeding a pseudo-random number generator with the result of encrypting something with a session key and a key usage value that isn't used for anything else) ๐Ÿง . Key usage values from 1024 to 2047 (inclusive) are reserved for applications, and applications SHOULD use even values for encryption and odd values for checksums in that range ๐ŸŽ€. Key usage values are also summed up in a table in Section 7.5.1 ๐Ÿ“‹.

Key usages 1024 and 1025 are the fallback. If no key usage values are specified, they are the ones that must be used to derive keys for encryption and checksums.

Hmm, I need to keep the original's exact meaning, so let me say it plainly without changing it. There might be other documents out there that define protocols in terms of the RFC 1510 encryption or checksum types. Those documents wouldn't know about key usages ๐Ÿ™ˆ. So that these specs stay meaningful until they get updated, if no key usage values are specified, then key usages 1024 and 1025 must be used to derive keys for encryption and checksums, respectively ๐Ÿ’œ. (This doesn't cover protocols that do their own encryption outside this framework, by using the key straight from the Kerberos authentication exchange.) New protocols defined in terms of the Kerberos encryption and checksum types SHOULD use their own key usage values ๐Ÿซถ.

Unless it's indicated otherwise, no cipher state chaining happens from one encryption operation to the next ๐Ÿ”—.

Implementation note: Even though it is not recommended, some application protocols will keep using the key data directly, even if it's only in protocol specs that already exist ๐Ÿ˜ฌ. So an implementation meant to support general Kerberos applications might need to make the key data available, along with the attributes and operations described in [RFC3961] ๐Ÿ› ๏ธ. One of the most common reasons to encrypt directly is to have direct control over choosing a "sufficiently strong" encryption algorithm for a given application ๐Ÿ’ช. Kerberos doesn't directly give you a way to negotiate encryption types between the application client and server, but there are approaches that use Kerberos to help with that negotiation. For example, a client can ask the KDC for only "sufficiently strong" session key types, and expect that the application server will understand and support any type the KDC sends back ๐ŸŒธ.


5. Message Specifications ๐Ÿ’Œ

The ASN.1 collected here should be identical to the contents of Appendix A. If they conflict, the contents of Appendix A shall take precedence ๐Ÿ“œ.

The Kerberos protocol is defined here in terms of Abstract Syntax Notation One (ASN.1) [X680], which gives you a syntax for describing both the abstract layout of protocol messages and how they get encoded ๐Ÿงฉ. Implementors who aren't using an existing ASN.1 compiler or support library should really understand the actual ASN.1 specification thoroughly so they get the implementation behavior right ๐Ÿ™. The notation is more complicated than it first looks, and some ASN.1 tutorials and guides are misleading or wrong ๐Ÿ˜ญ.

Note that in several places, abstract types have changed from RFC 1510. This partly addresses widespread assumptions that many implementors made, which in some cases led to accidental violations of the ASN.1 standard ๐Ÿ™ƒ. These changes are clearly flagged where they occur. The differences between the abstract types in RFC 1510 and the ones in this document can cause incompatible encodings when certain encoding rules are used, such as the Packed Encoding Rules (PER). This theoretical incompatibility should not be relevant for Kerberos, since Kerberos explicitly requires the Distinguished Encoding Rules (DER). It might be an issue for protocols that try to use Kerberos types with other encoding rules. (This practice is not recommended.) With very few exceptions (most notably the usages of BIT STRING), the encodings from using DER stay identical between the types in RFC 1510 and the types in this document ๐ŸŽ€.

The type definitions in this section assume an ASN.1 module definition of the following form:

KerberosV5Spec2 {
        iso(1) identified-organization(3) dod(6) internet(1)
        security(5) kerberosV5(2) modules(4) krb5spec2(2)
} DEFINITIONS EXPLICIT TAGS ::= BEGIN

-- rest of definitions here

END

This says the tagging context for the module is explicit and non-automatic ๐Ÿท๏ธ.

Note that in some other publications (like [RFC1510] and [RFC1964]), the "dod" part of the object identifier is wrongly given the value "5". For RFC 1964, using the "correct" OID value would change the wire protocol, so it stays unchanged for now ๐Ÿ™ˆ.

Note that nomenclature for message types is inconsistent elsewhere in this document, but it mostly follows C language conventions, including underscores (_) and all-caps names for things meant to be numeric constants ๐Ÿ”ค. Also, in some places, identifiers (especially ones for constants) are written in all caps so they stand out from the surrounding explanation โœจ.

ASN.1 doesn't allow underscores in identifiers, so in the actual ASN.1 definitions, underscores get swapped for hyphens (-). Also, structure member names and defined values in ASN.1 MUST begin with a lowercase letter, while type names MUST begin with an uppercase letter ๐Ÿ” .


5.1. Specific Compatibility Notes on ASN.1 ๐Ÿ•ฐ๏ธ

For compatibility, implementors should heed these specific notes about how ASN.1 is used in Kerberos. These notes don't describe deviations from standard ASN.1 usage. Instead, they describe some historical quirks and non-compliance in various implementations, plus historical ambiguities that, even though they're valid ASN.1, can cause confusion during implementation ๐Ÿค“.

5.1.1. ASN.1 Distinguished Encoding Rules

The encoding of Kerberos protocol messages shall obey the Distinguished Encoding Rules (DER) of ASN.1 as described in [X690]. Some implementations (believed to be mainly those derived from DCE 1.1 and earlier) are known to use the more general Basic Encoding Rules (BER). In particular, these implementations send indefinite encodings of lengths. Implementations MAY accept such encodings for the sake of backward compatibility, but implementors are warned that decoding fully general BER is fraught with peril ๐Ÿ’€.

5.1.2. Optional Integer Fields

Some implementations don't internally tell apart an omitted optional integer value from a transmitted value of zero ๐Ÿคทโ€โ™€๏ธ. The places in the protocol where this matters include various microseconds fields, nonces, and sequence numbers. Implementations SHOULD treat omitted optional integer values as if they had been transmitted with a value of zero, if the application expects that ๐Ÿซถ.

5.1.3. Empty SEQUENCE OF Types

There are places in the protocol where a message contains a SEQUENCE OF type as an optional member. That can result in an encoding that has an empty SEQUENCE OF encoding. The Kerberos protocol doesn't semantically tell apart an absent optional SEQUENCE OF type and a present but empty optional SEQUENCE OF type. Implementations SHOULD NOT send empty SEQUENCE OF encodings that are marked OPTIONAL, but SHOULD accept them as equivalent to an omitted OPTIONAL type. In the ASN.1 syntax describing Kerberos messages, these problem optional SEQUENCE OF types are marked with a comment ๐Ÿ’ฌ.

5.1.4. Unrecognized Tag Numbers

Future revisions of this protocol might add new message types with different APPLICATION class tag numbers ๐Ÿ”ฎ. Those revisions should protect older implementations by only sending the new message types to parties known to understand them, for example by using a flag bit that the receiver sets in an earlier request. For robust error handling, implementations SHOULD gracefully handle receiving a message with an unrecognized tag anyway, and return an error message if that's appropriate ๐Ÿ›ก๏ธ.

In particular, KDCs SHOULD return KRB_AP_ERR_MSG_TYPE if the wrong tag is sent over a TCP transport. KDCs SHOULD NOT respond to messages with an unknown tag over UDP transport, in order to avoid denial of service attacks ๐Ÿšซ. For non-KDC applications, the Kerberos implementation typically reports an error to the application, which then takes whatever steps make sense for its application protocol ๐Ÿงšโ€โ™€๏ธ.

5.1.5. Tag Numbers Greater Than 30 ๐ŸŒธ

okay bestie, heads up ๐Ÿซถ a naive DER ASN.1 decoder can totally trip over tag numbers bigger than 30, because those get encoded using more than one byte ๐Ÿ˜ญ. future versions of this protocol might use tag numbers above 30, so implementations SHOULD be prepared to gracefully return an error, if appropriate, when they don't recognize the tag โœจ

5.2. Basic Kerberos Types ๐Ÿ’…

this section defines a bunch of basic types that could show up in multiple Kerberos protocol messages ๐ŸŽ€

5.2.1. KerberosString ๐Ÿ’–

so the original Kerberos spec in RFC 1510 uses GeneralString all over the place for human-readable string data ๐Ÿ“. historical implementations can't use the full power of GeneralString, and honestly that's kind of a mood ๐Ÿ’€. this ASN.1 type needs designation and invocation escape sequences from ISO-2022/ECMA-35 [ISO-2022/ECMA-35] to switch character sets. the default character set designated as G0 is ISO-646/ECMA-6 [ISO-646/ECMA-6] International Reference Version (IRV) (a.k.a. U.S. ASCII), which mostly works ๐ŸŒธ

ISO-2022/ECMA-35 defines four character-set code elements (G0..G3) and two Control-function code elements (C0..C1) ๐Ÿฆ‹. DER prohibits designating character sets as anything but the G0 and C0 sets. unfortunately, this seems to have the side effect of prohibiting ISO-8859 (ISO Latin) [ISO-8859] character sets, or any other character sets that use a 96-character set, since ISO-2022/ECMA-35 prohibits designating them as the G0 code element. this side effect is being investigated in the ASN.1 standards community ๐Ÿ‘€

in practice, a lot of implementations treat GeneralStrings as if they were 8-bit strings of whatever character set the implementation defaults to, without caring about correct usage of the character-set designation escape sequences ๐Ÿ™ˆ. the default is often determined by the current user's operating-system-dependent locale. at least one major implementation puts unescaped UTF-8 encoded Unicode characters in the GeneralString, and this failure to follow the GeneralString specs leads to interoperability issues when clients, services, and the KDC are using conflicting character encodings ๐Ÿ˜ญ

this whole mess is the result of improper documentation of the restrictions on the ASN.1 GeneralString type in earlier Kerberos specs. not it ๐Ÿ™ƒ

the new (post-RFC 1510) type KerberosString, defined below, is a GeneralString that's constrained to contain only characters in IA5String ๐Ÿงš

KerberosString  ::= GeneralString (IA5String)

in general, US-ASCII control characters should not be used in KerberosString. Control characters SHOULD NOT be used in principal names or realm names ๐Ÿšซ

for compatibility, implementations MAY choose to accept GeneralString values that contain characters other than those permitted by IA5String. they should be aware that character set designation codes will likely be absent, and that the encoding should probably be treated as locale-specific in almost every way ๐ŸŒˆ. implementations MAY also choose to emit GeneralString values that go beyond those permitted by IA5String, but they should be aware that doing so is extraordinarily risky from an interoperability perspective ๐Ÿ’€

some existing implementations use GeneralString to encode unescaped locale-specific characters. this is a violation of the ASN.1 standard. most of these implementations encode US-ASCII in the left-hand half, so as long as the implementation only transmits US-ASCII, the ASN.1 standard isn't violated in this regard. as soon as one of them encodes unescaped locale-specific characters with the high bit set, it violates the ASN.1 standard ๐Ÿ™ƒ

other implementations have been known to use GeneralString to contain a UTF-8 encoding. that also violates the ASN.1 standard, since UTF-8 is a different encoding, not a 94 or 96 character "G" set as defined by ISO 2022 ๐Ÿซ . it's believed these implementations don't even use the ISO 2022 escape sequence to change the character encoding. even if they did announce the encoding change with that escape sequence, the ASN.1 standard prohibits any escape sequences other than the ones used to designate or invoke "G" or "C" sets allowed by GeneralString ๐Ÿ’…

future revisions of this protocol will almost certainly allow for a more interoperable representation of principal names, probably including UTF8String โœจ

also, applying a new constraint to a previously unconstrained type creates a new ASN.1 type. in this particular case, the change doesn't result in a changed encoding under DER ๐ŸŽ€

5.2.2. Realm and PrincipalName ๐Ÿ‘‘

Realm           ::= KerberosString

PrincipalName   ::= SEQUENCE {
        name-type       [0] Int32,
        name-string     [1] SEQUENCE OF KerberosString
}

Kerberos realm names are encoded as KerberosStrings. Realms shall not contain a character with the code 0 (the US-ASCII NUL) ๐Ÿ’…. most realms will usually consist of several components separated by periods (.), in the style of Internet Domain Names, or separated by slashes (/), in the style of X.500 names. acceptable forms for realm names are specified in Section 6.1. a PrincipalName is a typed sequence of components made up of these subfields:

  • name-type: this field specifies the type of name that follows. pre-defined values for this field are specified in Section 6.2. The name-type SHOULD be treated as a hint. ignoring the name type, no two names can be the same (i.e., at least one of the components, or the realm, must be different) ๐Ÿง 
  • name-string: this field encodes a sequence of components that form a name, with each component encoded as a KerberosString. taken together, a PrincipalName and a Realm form a principal identifier ๐Ÿฆ‹. most PrincipalNames will have only a few components (typically one or two)

5.2.3. KerberosTime โฐ

KerberosTime    ::= GeneralizedTime -- with no fractional seconds

the timestamps used in Kerberos are encoded as GeneralizedTimes. a KerberosTime value shall not include any fractional portions of the seconds. as required by the DER, it further shall not include any separators, and it shall specify the UTC time zone (Z) ๐ŸŒธ. example: the only valid format for UTC time 6 minutes, 27 seconds after 9 pm on 6 November 1985 is 19851106210627Z ๐Ÿงš

5.2.4. Constrained Integer Types ๐Ÿ”ข

some integer members of types SHOULD be constrained to values representable in 32 bits, for compatibility with reasonable implementation limits ๐Ÿ’–

Int32           ::= INTEGER (-2147483648..2147483647)
                    -- signed values representable in 32 bits

UInt32          ::= INTEGER (0..4294967295)
                    -- unsigned 32 bit values

Microseconds    ::= INTEGER (0..999999)
                    -- microseconds

even though this changes the abstract types from the RFC 1510 version, the encoding in DER should be unaltered. historical implementations were typically limited to 32-bit integer values anyway, and assigned numbers SHOULD fall in the space of integer values representable in 32 bits, to promote interoperability anyway ๐Ÿซถ

several integer fields in messages are constrained to fixed values:

  • pvno (also TKT-VNO or AUTHENTICATOR-VNO): this recurring field is always the constant integer 5. there's no easy way to make this field into a useful protocol version number, so its value is fixed ๐Ÿ”’
  • msg-type: this integer field is usually identical to the application tag number of the containing message type ๐Ÿท๏ธ

5.2.5. HostAddress and HostAddresses ๐Ÿ 

HostAddress     ::= SEQUENCE  {
        addr-type       [0] Int32,
        address         [1] OCTET STRING
}

-- NOTE: HostAddresses is always used as an OPTIONAL field and
-- should not be empty.
HostAddresses   -- NOTE: subtly different from rfc1510,
                -- but has a value mapping and encodes the same
        ::= SEQUENCE OF HostAddress

the host address encodings consist of two fields:

  • addr-type: this field specifies the type of address that follows. Pre-defined values for this field are specified in Section 7.5.3 ๐Ÿ“
  • address: this field encodes a single address of type addr-type ๐Ÿ“ฌ

5.2.6. AuthorizationData ๐ŸŽŸ๏ธ

-- NOTE: AuthorizationData is always used as an OPTIONAL field and
-- should not be empty.
AuthorizationData       ::= SEQUENCE OF SEQUENCE {
        ad-type         [0] Int32,
        ad-data         [1] OCTET STRING
}
  • ad-data: this field contains authorization data to be interpreted according to the value of the corresponding ad-type field ๐Ÿ“ฆ
  • ad-type: this field specifies the format for the ad-data subfield. All negative values are reserved for local use. Non-negative values are reserved for registered use ๐Ÿ—‚๏ธ

each sequence of type and data is called an authorization element. Elements MAY be application specific; however, there's a common set of recursive elements that should be understood by all implementations ๐Ÿ’œ. these elements contain other elements embedded within them, and the interpretation of the encapsulating element decides which of the embedded elements must be interpreted, and which ones may be ignored ๐Ÿง

these common authorization data elements are recursively defined, meaning the ad-data for these types will itself contain a sequence of authorization data whose interpretation is affected by the encapsulating element. depending on what the encapsulating element means, the encapsulated elements may be ignored, might be interpreted as issued directly by the KDC, or might be stored in a separate plaintext part of the ticket. the types of the encapsulating elements are specified as part of the Kerberos specification, because the behavior based on these values should be understood across implementations, whereas other elements only need to be understood by the applications they affect ๐ŸŒˆ

authorization data elements are considered critical if present in a ticket or authenticator. if an unknown authorization data element type is received by a server, either in an AP-REQ or in a ticket contained in an AP-REQ, then, unless it's encapsulated in a known authorization data element that amends the criticality of the elements it contains, authentication MUST fail ๐Ÿšจ. authorization data is intended to restrict the use of a ticket. if the service can't determine whether the restriction applies to that service, then a security weakness may result if the ticket can be used for that service ๐Ÿ’€. authorization elements that are optional can be enclosed in an AD-IF-RELEVANT element ๐Ÿซถ

in the definitions that follow, the value of the ad-type for the element is specified as the least significant part of the subsection number, and the value of the ad-data is as shown in the ASN.1 structure that follows the subsection heading โœจ

Contents of ad-data                ad-type

DER encoding of AD-IF-RELEVANT        1

DER encoding of AD-KDCIssued          4

DER encoding of AD-AND-OR             5

DER encoding of AD-MANDATORY-FOR-KDC  8

5.2.6.1. IF-RELEVANT ๐ŸŽ€

AD-IF-RELEVANT          ::= AuthorizationData

okay bestie, so AD elements tucked inside the if-relevant wrapper are only meant for application servers that actually understand that embedded ad-type ๐Ÿ’…. If an application server doesn't understand the type of an element inside it, that server MAY ignore the uninterpretable element ๐Ÿ™ˆ. This is giving interoperability queen ๐Ÿ‘‘, because implementations can have their own local extensions for authorization and still play nice together ๐Ÿฆ‹. The ad-type for AD-IF-RELEVANT is (1) โœจ.

5.2.6.2. KDCIssued ๐Ÿ”

AD-KDCIssued            ::= SEQUENCE {
        ad-checksum     [0] Checksum,
        i-realm         [1] Realm OPTIONAL,
        i-sname         [2] PrincipalName OPTIONAL,
        elements        [3] AuthorizationData
}

here's the breakdown of the fields ๐Ÿ’–

  • ad-checksum: a cryptographic checksum computed over the DER encoding of the AuthorizationData in the "elements" field, keyed with the session key. Its checksumtype is the mandatory checksum type for the encryption type of the session key, and its key usage value is 19 ๐ŸŒธ
  • i-realm and i-sname: the name of the issuing principal, but only if it's different from the KDC itself. This field would be used when the KDC can verify the authenticity of elements signed by the issuing principal, and it lets this KDC tell the application server whether those elements are valid ๐Ÿงš
  • elements: a sequence of authorization data elements issued by the KDC โญ

the KDC-issued ad-data field is basically a way for Kerberos principal credentials to carry their own privilege attributes and other mechanisms for positive authorization, boosting the principal's privileges beyond what's possible with credentials that don't have an ad-data element like this ๐Ÿ‘‘โœจ

the above can't be done without this element, because the authorization-data field lets whoever holds a TGT add elements at will when they request service tickets, and elements can also be added to a delegated ticket by putting them in the authenticator ๐Ÿ’€

for KDC-issued elements, this gets blocked because the KDC signs them by including a checksum encrypted with the server's key (the same key used to encrypt the ticket, or a key derived from that key) ๐Ÿ”ฅ elements encapsulated within the KDC-issued element MUST be ignored by the application server if this "signature" is not present ๐Ÿ™…โ€โ™€๏ธ also, elements inside this element that come from a TGT MAY be interpreted by the KDC and used, according to policy, as a basis for including new signed elements in derivative tickets, but they will NOT be copied directly into a derivative ticket. if a KDC that doesn't know about this element copies them over directly anyway, the signature won't be correct for the application ticket elements, and the application server will ignore that field ๐Ÿ˜ญ

this element and the elements it encapsulates MAY safely be ignored by applications, application servers, and KDCs that don't implement it ๐Ÿซถ

the ad-type for AD-KDC-ISSUED is (4) ๐ŸŒˆ

โš ๏ธ reminder: the MUST and MAY rules above are not optional vibes. the "signature" check is what keeps these elements trustworthy.

5.2.6.3. AND-OR ๐Ÿ“

AD-AND-OR               ::= SEQUENCE {
        condition-count [0] Int32,
        elements        [1] AuthorizationData
}

when restrictive AD elements are wrapped inside the and-or element, the and-or element counts as satisfied if and only if at least the number of encapsulated elements listed in condition-count are satisfied ๐Ÿง  so this element MAY be used to build an "or" operation by setting condition-count to 1, and it MAY specify an "and" operation by setting condition-count to the number of embedded elements ๐Ÿ’œ application servers that don't implement this element MUST reject tickets containing authorization data elements of this type ๐Ÿšซ

the ad-type for AD-AND-OR is (5) ๐Ÿฆ‹

5.2.6.4. MANDATORY-FOR-KDC ๐Ÿ“œ

AD-MANDATORY-FOR-KDC    ::= AuthorizationData

AD elements wrapped inside the mandatory-for-kdc element are meant to be interpreted by the KDC ๐Ÿ‘€ KDCs that don't understand the type of an element embedded in here MUST reject the request ๐Ÿ™…โ€โ™€๏ธ

the ad-type for AD-MANDATORY-FOR-KDC is (8) ๐Ÿ’…

5.2.7. PA-DATA ๐ŸŒธ

historically, PA-DATA was known as "pre-authentication data", meaning it was used to augment the initial authentication with the KDC ๐Ÿ•ฐ๏ธ but since then, it's also been used as a typed hole for extending protocol exchanges with the KDC, which is so iconic ๐Ÿงšโ€โ™€๏ธ

PA-DATA         ::= SEQUENCE {
        -- NOTE: first tag is [1], not [0]
        padata-type     [1] Int32,
        padata-value    [2] OCTET STRING -- might be encoded AP-REQ
}
  • padata-type: tells you how to interpret the padata-value element. Negative values are reserved for unregistered use, and non-negative values are used for a registered interpretation of the element type ๐Ÿ”ข
  • padata-value: usually contains the DER encoding of another type, and the padata-type field tells you which type is encoded there โœจ
padata-type  Name             Contents of padata-value

1            pa-tgs-req       DER encoding of AP-REQ

2            pa-enc-timestamp DER encoding of PA-ENC-TIMESTAMP

3            pa-pw-salt       salt (not ASN.1 encoded)

11           pa-etype-info    DER encoding of ETYPE-INFO

19           pa-etype-info2   DER encoding of ETYPE-INFO2

this field MAY also contain info needed by certain extensions to the Kerberos protocol ๐Ÿ’ซ for example, it might verify a client's identity before any response goes back ๐Ÿ”

the padata field can also carry info that helps the KDC or the client pick the key needed for generating or decrypting the response ๐Ÿ”‘ this is super useful for supporting certain token cards with Kerberos ๐Ÿ’ณ the details of those extensions live in separate documents ๐Ÿ“š see [Pat92] for more uses of this field ๐ŸŒˆ

5.2.7.1. PA-TGS-REQ ๐ŸŽซ

for requests for additional tickets (KRB_TGS_REQ), padata-value will contain an encoded AP-REQ ๐Ÿ’Œ the checksum in the authenticator (which MUST be collision-proof) gets computed over the KDC-REQ-BODY encoding ๐Ÿ”

5.2.7.2. Encrypted Timestamp Pre-authentication โฐ

there are pre-authentication types that can pre-authenticate a client using an encrypted timestamp โœจ

PA-ENC-TIMESTAMP        ::= EncryptedData -- PA-ENC-TS-ENC

PA-ENC-TS-ENC           ::= SEQUENCE {
        patimestamp     [0] KerberosTime -- client's time --,
        pausec          [1] Microseconds OPTIONAL
}

patimestamp holds the client's time, and pausec holds the microseconds ๐Ÿ• pausec MAY be omitted if a client won't generate more than one request per second ๐Ÿƒโ€โ™€๏ธ the ciphertext (padata-value) is the PA-ENC-TS-ENC encoding, encrypted using the client's secret key and a key usage value of 1 ๐Ÿฆ‹

this pre-authentication type wasn't in RFC 1510, but lots of implementations support it ๐Ÿซถ

5.2.7.3. PA-PW-SALT ๐Ÿง‚

the padata-value for this pre-authentication type contains the salt for the string-to-key that the client uses to get the key for decrypting the encrypted part of an AS-REP message ๐Ÿ”‘ unfortunately, for historical reasons, the character set is unspecified and probably locale-specific ๐ŸŒ (not ideal, bestie ๐Ÿ˜ญ)

this pre-authentication type wasn't in RFC 1510, but many implementations support it ๐Ÿ’œ it's necessary in any case where the salt for the string-to-key algorithm isn't the default ๐ŸŽ€

in the simplest example, a zero-length salt string is super common for realms that converted their principal databases from Kerberos Version 4 ๐ŸŒธ

a KDC SHOULD NOT send PA-PW-SALT when issuing a KRB-ERROR message that requests additional pre-authentication ๐Ÿšซ

๐Ÿ› ๏ธ implementation note: some KDC implementations send an erroneous PA-PW-SALT when issuing a KRB-ERROR message that requests additional pre-authentication. so clients SHOULD ignore a PA-PW-SALT that comes with a KRB-ERROR message requesting additional pre-authentication ๐Ÿ™ˆ

as noted in section 3.1.3, a KDC MUST NOT send PA-PW-SALT when the client's AS-REQ includes at least one "newer" etype ๐Ÿšซโœจ

5.2.7.4. PA-ETYPE-INFO ๐Ÿ—๏ธ

the ETYPE-INFO pre-authentication type is sent by the KDC in a KRB-ERROR that indicates a requirement for additional pre-authentication ๐Ÿ’Œ it's usually used to tell a client which key to use for encrypting an encrypted timestamp, for the purposes of sending a PA-ENC-TIMESTAMP pre-authentication value ๐Ÿ” it MAY also be sent in an AS-REP to tell the client which key salt to use for the string-to-key, so the client can get the key for decrypting the encrypted part of the AS-REP ๐Ÿงš

ETYPE-INFO-ENTRY        ::= SEQUENCE {
        etype           [0] Int32,
        salt            [1] OCTET STRING OPTIONAL
}

ETYPE-INFO              ::= SEQUENCE OF ETYPE-INFO-ENTRY

the salt, like PA-PW-SALT's, is also completely unspecified when it comes to character set and is probably locale-specific ๐ŸŒ

if ETYPE-INFO is sent in an AS-REP, there shall be exactly one ETYPE-INFO-ENTRY, and its etype shall match that of the enc-part in the AS-REP ๐ŸŽฏ

this pre-authentication type wasn't in RFC 1510, but many implementations that support encrypted timestamps for pre-authentication need ETYPE-INFO as well ๐Ÿ’– as noted in Section 3.1.3, a KDC MUST NOT send PA-ETYPE-INFO when the client's AS-REQ includes at least one "newer" etype ๐Ÿšซ

5.2.7.5. PA-ETYPE-INFO2 ๐ŸŒŸ

the ETYPE-INFO2 pre-authentication type is sent by the KDC in a KRB-ERROR that indicates a requirement for additional pre-authentication ๐ŸŽ€ it's usually used to tell a client which key to use for encrypting an encrypted timestamp, for the purposes of sending a PA-ENC-TIMESTAMP pre-authentication value ๐Ÿ” it MAY also be sent in an AS-REP to tell the client which key salt to use for the string-to-key, so the client can get the key for decrypting the encrypted part of the AS-REP ๐Ÿงšโ€โ™€๏ธ

ETYPE-INFO2-ENTRY       ::= SEQUENCE {
        etype           [0] Int32,
        salt            [1] KerberosString OPTIONAL,
        s2kparams       [2] OCTET STRING OPTIONAL
}

ETYPE-INFO2              ::= SEQUENCE SIZE (1..MAX) OF ETYPE-INFO2-ENTRY

the salt's type is KerberosString, but existing installations might have locale-specific characters stored in salt strings, and implementors MAY choose to handle them ๐ŸŒ๐Ÿ’…

the interpretation of s2kparams is specified in the cryptosystem description tied to the etype ๐Ÿงช each cryptosystem has a default interpretation of s2kparams that applies if that element is left out of the ETYPE-INFO2-ENTRY encoding โœจ

if ETYPE-INFO2 is sent in an AS-REP, there shall be exactly one ETYPE-INFO2-ENTRY, and its etype shall match that of the enc-part in the AS-REP ๐ŸŽฏ

the preferred ordering of the "hint" pre-authentication data that affects client key selection is: ETYPE-INFO2, then ETYPE-INFO, then PW-SALT ๐Ÿฅ‡ as noted in Section 3.1.3, a KDC MUST NOT send ETYPE-INFO or PW-SALT when the client's AS-REQ includes at least one "newer" etype ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’œ

the ETYPE-INFO2 pre-authentication type wasn't in RFC 1510 ๐ŸŒธ

5.2.8. KerberosFlags โœจ

Okay so for a bunch of message types, Kerberos uses a special bit string type called KerberosFlags ๐ŸŽ€ It's basically a compact row of on/off switches, and it's giving very specific vibes ๐Ÿ’…

KerberosFlags   ::= BIT STRING (SIZE (32..MAX))
                    -- minimum number of bits shall be sent,
                    -- but no fewer than 32

Compatibility note: this next part describes a change from the RFC 1510 description of bit strings. It would break an implementation that strictly followed ASN.1 DER and RFC 1510 ๐Ÿ™ˆ

ASN.1 bit strings have a few jobs. The simplest one is just holding a vector of bits with no special meaning for any individual bit, and that vector doesn't have to be a multiple of eight bits long ๐Ÿงš Kerberos wants something different: a bit string used as a compact boolean vector, where every bit has its own meaning. The natural way to write that is the ASN.1 "NamedBit" notation, but DER says that encodings using "NamedBit" notation have to leave off any trailing zero bits. That truncation is super easy to forget, especially in C implementations, which tend to store boolean vectors as 32-bit integers ๐Ÿ˜ญ

Here's an example. Say the KDCOptions notation included "NamedBit" like RFC 1510 did, and you were encoding a KDCOptions value where only the "forwardable" bit (bit number one) was set. The DER encoding MUST include only two bits: the first reserved bit ("reserved", bit number zero, value zero) and the one-valued bit (bit number one) for "forwardable". Bestie, that's the whole thing ๐Ÿ’–

Most existing Kerberos implementations just send 32 bits on the wire whenever they encode a bit string used as a boolean vector. That breaks the ASN.1 syntax RFC 1510 used for flag values, but the install base is so huge that this protocol description is being changed to accommodate it ๐ŸŒˆ

So this document takes the "NamedBit" notations for individual bits out and moves them into comments. The size constraint on KerberosFlags means at least 32 bits have to be encoded every time. A lenient implementation MAY choose to accept fewer than 32 bits, though, and treat the missing bits as set to zero ๐Ÿซถ

Right now no use of KerberosFlags needs more than 32 bits of flags, but future revisions of this document might. If more than 32 bits ever get sent in a KerberosFlags value, future revisions will probably say to send the smallest number of bits needed to encode the highest-numbered one-valued bit. That's kind of similar to how DER encodes a bit string declared with the "NamedBit" notation ๐Ÿฆ‹

Lots of Kerberos messages carry an EncryptedData as a container for arbitrary encrypted data. Usually that data is the encrypted encoding of some other data type. The fields inside EncryptedData help the recipient pick the right key to decrypt what's inside ๐Ÿ”ฅ

EncryptedData   ::= SEQUENCE {
        etype   [0] Int32 -- EncryptionType --,
        kvno    [1] UInt32 OPTIONAL,
        cipher  [2] OCTET STRING -- ciphertext
}

etype: this field says which encryption algorithm was used to encipher the cipher.

kvno: this field has the version number of the key the data is encrypted under. It only shows up in messages encrypted under long-lasting keys, like principals' secret keys ๐Ÿ”‘

cipher: this field holds the enciphered text, encoded as an OCTET STRING. (Also, the encryption mechanisms defined in [RFC3961] MUST incorporate integrity protection as well, so you don't need any extra checksum. Iconic, right? ๐Ÿ’…)

The EncryptionKey type is how cryptographic keys used for encryption get transferred ๐ŸŽ€

EncryptionKey   ::= SEQUENCE {
        keytype         [0] Int32 -- actually encryption type --,
        keyvalue        [1] OCTET STRING
}

keytype: this field specifies the encryption type of the key in the keyvalue field that follows. Even though it's called "keytype", it actually specifies an encryption type ๐Ÿ™ƒ Back in the day, cryptosystems that encrypted differently but could use keys with the same characteristics were allowed to share one assigned number for the key type. That usage is deprecated now.

keyvalue: this field contains the key itself, encoded as an octet string.

Messages with cleartext data that needs authenticating will usually do it with a Checksum member. Most Checksum instances use a keyed hash, but the exceptions will be called out ๐Ÿ’œ

Checksum        ::= SEQUENCE {
        cksumtype       [0] Int32,
        checksum        [1] OCTET STRING
}

cksumtype: this field says which algorithm made the accompanying checksum.

checksum: this field contains the checksum itself, encoded as an octet string.

For a quick rundown of how encryption and checksums get used in Kerberos, see Section 4 โœจ

5.3. Tickets ๐ŸŽŸ๏ธ

This section covers the format and encryption parameters for tickets and authenticators. When a ticket or authenticator shows up in a protocol message, it's treated as an opaque object ๐Ÿซฃ A ticket is a record that helps a client authenticate to a service. A Ticket has the following information:

Ticket          ::= [APPLICATION 1] SEQUENCE {
        tkt-vno         [0] INTEGER (5),
        realm           [1] Realm,
        sname           [2] PrincipalName,
        enc-part        [3] EncryptedData -- EncTicketPart
}

-- Encrypted part of ticket
EncTicketPart   ::= [APPLICATION 3] SEQUENCE {
        flags                   [0] TicketFlags,
        key                     [1] EncryptionKey,
        crealm                  [2] Realm,
        cname                   [3] PrincipalName,
        transited               [4] TransitedEncoding,
        authtime                [5] KerberosTime,
        starttime               [6] KerberosTime OPTIONAL,
        endtime                 [7] KerberosTime,
        renew-till              [8] KerberosTime OPTIONAL,
        caddr                   [9] HostAddresses OPTIONAL,
        authorization-data      [10] AuthorizationData OPTIONAL
}

-- encoded Transited field
TransitedEncoding       ::= SEQUENCE {
        tr-type         [0] Int32 -- must be registered --,
        contents        [1] OCTET STRING
}

TicketFlags     ::= KerberosFlags
        -- reserved(0),
        -- forwardable(1),
        -- forwarded(2),
        -- proxiable(3),
        -- proxy(4),
        -- may-postdate(5),
        -- postdated(6),
        -- invalid(7),
        -- renewable(8),
        -- initial(9),
        -- pre-authent(10),
        -- hw-authent(11),
-- the following are new since 1510
        -- transited-policy-checked(12),
        -- ok-as-delegate(13)

tkt-vno: this field specifies the version number of the ticket format. This document describes version number 5 โœจ

realm: this field says which realm issued the ticket. It also identifies the realm part of the server's principal identifier. A Kerberos server can only issue tickets for servers inside its own realm, so the two are always identical ๐Ÿ‘‘

sname: this field specifies every component of the name part of the server's identity, including the parts that identify a specific instance of a service ๐Ÿงš

enc-part: this field holds the encrypted encoding of the EncTicketPart sequence. It's encrypted under the key shared by Kerberos and the end server (the server's secret key), using a key usage value of 2 ๐Ÿ”

flags: this field shows which options were used or requested when the ticket was issued. Here's what the flags mean:

Bit(s)  Name             Description

0       reserved         Reserved for future expansion of this field.

1       forwardable      The FORWARDABLE flag is normally only
                         interpreted by the TGS, and can be ignored
                         by end servers.  When set, this flag tells
                         the ticket-granting server that it is OK to
                         issue a new TGT with a different network
                         address based on the presented ticket.

2       forwarded        When set, this flag indicates that the
                         ticket has either been forwarded or was
                         issued based on authentication involving a
                         forwarded TGT.

3       proxiable        The PROXIABLE flag is normally only
                         interpreted by the TGS, and can be ignored
                         by end servers.  The PROXIABLE flag has an
                         interpretation identical to that of the
                         FORWARDABLE flag, except that the PROXIABLE
                         flag tells the ticket-granting server that
                         only non-TGTs may be issued with different
                         network addresses.

4       proxy            When set, this flag indicates that a ticket
                         is a proxy.

5       may-postdate     The MAY-POSTDATE flag is normally only
                         interpreted by the TGS, and can be ignored
                         by end servers.  This flag tells the
                         ticket-granting server that a post-dated
                         ticket MAY be issued based on this TGT.

6       postdated        This flag indicates that this ticket has
                         been postdated.  The end-service can check
                         the authtime field to see when the original
                         authentication occurred.

7       invalid          This flag indicates that a ticket is
                         invalid, and it must be validated by the KDC
                         before use.  Application servers must reject
                         tickets which have this flag set.

8       renewable        The RENEWABLE flag is normally only
                         interpreted by the TGS, and can usually be
                         ignored by end servers (some particularly
                         careful servers MAY disallow renewable
                         tickets).  A renewable ticket can be used to
                         obtain a replacement ticket that expires at
                         a later date.

9       initial          This flag indicates that this ticket was
                         issued using the AS protocol, and not issued
                         based on a TGT.

10      pre-authent      This flag indicates that during initial
                         authentication, the client was authenticated
                         by the KDC before a ticket was issued.  The
                         strength of the pre-authentication method is
                         not indicated, but is acceptable to the KDC.

Okay, so the ticket flags keep going, and bestie, these are the flags that tell the server what kind of trust the ticket carries ๐Ÿฆ‹

   11      hw-authent       This flag indicates that the protocol
                            employed for initial authentication required
                            the use of hardware expected to be possessed
                            solely by the named client.  The hardware
                            authentication method is selected by the KDC
                            and the strength of the method is not
                            indicated.

   12      transited-       This flag indicates that the KDC for
           policy-checked   the realm has checked the transited field
                            against a realm-defined policy for trusted
                            certifiers.  If this flag is reset (0), then
                            the application server must check the
                            transited field itself, and if unable to do
                            so, it must reject the authentication.  If
                            the flag is set (1), then the application
                            server MAY skip its own validation of the
                            transited field, relying on the validation
                            performed by the KDC.  At its option the
                            application server MAY still apply its own
                            validation based on a separate policy for
                            acceptance.

                            This flag is new since RFC 1510.

   13      ok-as-delegate   This flag indicates that the server (not the
                            client) specified in the ticket has been
                            determined by policy of the realm to be a
                            suitable recipient of delegation.  A client
                            can use the presence of this flag to help it
                            decide whether to delegate credentials
                            (either grant a proxy or a forwarded TGT) to
                            this server.  The client is free to ignore
                            the value of this flag.  When setting this
                            flag, an administrator should consider the
                            security and placement of the server on
                            which the service will run, as well as
                            whether the service requires the use of
                            delegated credentials.

                            This flag is new since RFC 1510.

   14-31   reserved         Reserved for future use.

hw-authent (flag 11) says the first login used hardware that only the named client should have, like a security key ๐Ÿ”. The KDC picks that hardware method, but the flag doesn't say how strong it is, so don't assume it's bulletproof, babe ๐Ÿ’…

transited-policy-checked (flag 12) is all about the transited field. If it's reset (0), the application server has to check that field itself, and if it can't, it has to reject the authentication, no excuses ๐Ÿ™…โ€โ™€๏ธ If it's set (1), the application server MAY skip its own check and trust the KDC's check instead. It can still run its own check with a separate acceptance policy if it wants to, because it's the server's call โœจ This flag is new since RFC 1510 ๐ŸŒธ

ok-as-delegate (flag 13) means the realm's policy has said the server named in the ticket (not the client!) is a good place to send delegated credentials ๐Ÿงš The client can look at this flag to decide whether to hand over a proxy or a forwarded TGT, but it's totally free to ignore it ๐Ÿ’œ Admins, though, should think hard about how secure the server is and where it's sitting, plus whether the service even needs delegated credentials at all ๐Ÿ›ก๏ธ This flag is new since RFC 1510 ๐ŸŽ€

Flags 14-31 are reserved for future use ๐ŸŒˆ


Now the fields. These are the bits that hold the actual ticket info, so pay attention โœจ

key is in the ticket and in the KDC response. It's how the session key gets passed from Kerberos to both the application server and the client ๐Ÿ”‘

crealm is the realm where the client is registered and where the first authentication happened ๐Ÿฐ

cname holds the name part of the client's principal identifier ๐Ÿชช

transited lists the names of the Kerberos realms that helped authenticate the user this ticket was issued to. The order the realms were passed through is NOT part of it, so don't go looking for a sequence ๐Ÿ™…โ€โ™€๏ธ Check out Section 3.3.3.2 for how the traversed realms actually get encoded. When CA names are meant to go in the transited field (some protocol extensions do this), the X.500 names of those CAs SHOULD be mapped into transited items using the mapping defined by RFC 2253 ๐Ÿ“š

authtime is the time of the principal's initial authentication, which is the issue time of the original ticket this one is based on โฐ It's in the ticket so the end service gets extra info, and so the KDC can run a "hot list" service. A super paranoid end service could refuse tickets whose initial authentication was "too far" in the past ๐Ÿ˜ค It also comes back in the KDC response. In a KRB_AS_REP, it's the current time on the Kerberos server ๐Ÿ•ฐ๏ธ It is NOT recommended that you use this time to set the workstation's clock, because the workstation can't reliably confirm that the KRB_AS_REP really came from the right KDC in a timely way ๐Ÿšซ

starttime is the time after which the ticket is valid ๐ŸŒ… Together with endtime, it sets the ticket's life. If starttime is missing from the ticket, authtime SHOULD be used in its place to figure out the ticket's life ๐Ÿ’ซ

endtime is when the ticket stops being honored, its expiration time ๐Ÿฅ€ Heads up: individual services MAY put their own limits on a ticket's life, and they MAY reject tickets that haven't expired yet. So think of endtime as an upper bound on expiration, not a guarantee ๐Ÿ’€

renew-till only shows up in tickets with the RENEWABLE flag set in the flags field ๐Ÿ” It's the latest endtime a renewal can get, so you can think of it as the ticket's absolute expiration, renewals and all ๐ŸŽŸ๏ธ

caddr holds zero (if left out) or more host addresses, which are the places the ticket can be used from. No addresses means the ticket works from anywhere ๐ŸŒ Whether the KDC issues addressless tickets, or the end server accepts them, is a policy call left to the Kerberos and end-service admins, and they MAY refuse to issue or accept them ๐Ÿ™ˆ Since network address translation is everywhere now, it's recommended that policy allows issuing and accepting these tickets ๐Ÿซถ

Addresses are in the ticket to make life harder for attackers who steal credentials ๐Ÿ•ต๏ธโ€โ™€๏ธ The session key never travels over the network in cleartext, so just sniffing the wire won't steal a ticket. The attacker needs the session key too, maybe from an OS breach or someone's unlocked laptop, before the stolen ticket is any use ๐Ÿ’ป

Network addresses can't be reliably determined from where a connection comes in. Even if they could, an attacker who has compromised the client's workstation could use the credentials from there. Addresses only make it harder, not impossible, for someone to walk off with stolen credentials and then use them from a "safe" spot. Don't treat them as a security blanket, bestie ๐Ÿ˜ญ

authorization-data carries authorization data from the principal the ticket was issued for over to the application service ๐ŸŽซ If there's no authorization data, the field is left out. Honestly, the name is confusing. A better name would've been "restrictions", but it can't be changed now ๐Ÿ™ƒ

This field holds restrictions on any authority you get from authenticating with the ticket. Anyone holding credentials can add entries, since entries only narrow what the ticket can do. They can add them by asking for a new ticket during the TGS exchange, or they MAY add them during chained delegation through the authenticator's authorization data field ๐Ÿ”—

Here's the rule that matters: since credential holders can add entries, an entry in a ticket's authorization data can never amplify the privileges you'd get from the ticket. The only exception is when an entry is separately authenticated by being wrapped in the KDC-issued element, so the KDC vouched for it ๐Ÿ›ก๏ธ

The data here can be specific to the end service. The field holds the names of service-specific objects and the rights to those objects ๐Ÿ—‚๏ธ Kerberos doesn't care what's inside the subfields, but it does carry type information through ad-type ๐Ÿท๏ธ The format is described in Section 5.2.6 ๐Ÿ“–

With authorization-data, a principal can issue a proxy that's only valid for one purpose โœจ For example, a client who wants to print a file can get a file server proxy and pass it to the print server. By naming the file in the field, the file server knows the print server can only use the client's rights for that one file ๐Ÿ–จ๏ธ

A separate service that grants authorization or certifies group membership can use this field too ๐Ÿ‘‘ In that setup, the entity granting the authority (not the one getting it) can get a ticket in its own name, like a privilege server's. It adds restrictions to its own authority and delegates that restricted authority to the client through a proxy ๐Ÿค The client then shows that authorization credential to the application server separately from the authentication exchange. Or, the authorization credentials MAY be embedded in the ticket that authenticates the authorized entity, as long as the authorization is separately authenticated with the KDC-issued authorization data element (see 5.2.6.2) ๐Ÿงฉ

Also, if you set up the authorization-data field of a proxy and leave the host addresses blank, the resulting ticket and session key can be treated as a capability ๐Ÿฆ‹ See [Neu93] for some suggested uses of this field ๐Ÿ“Ž

The authorization-data field is optional, so a ticket doesn't have to include it ๐ŸŒธ


5.4. Specifications for the AS and TGS Exchanges โœจ

This section lays out the format of the messages exchanged between the client and the Kerberos server ๐Ÿ’Œ The format for possible error messages is in Section 5.9.1 ๐Ÿšจ

5.4.1. KRB_KDC_REQ Definition

The KRB_KDC_REQ message doesn't have its own application tag number ๐Ÿ™…โ€โ™€๏ธ Instead, it gets folded into either KRB_AS_REQ or KRB_TGS_REQ, and each of those has its own application tag. Which one you use depends on whether you're asking for an initial ticket or an additional one ๐ŸŽŸ๏ธ Either way, the message goes from the client to the KDC to request credentials for a service ๐Ÿซถ

The message fields are as follows:

AS-REQ          ::= [APPLICATION 10] KDC-REQ

TGS-REQ         ::= [APPLICATION 12] KDC-REQ

KDC-REQ         ::= SEQUENCE {
        -- NOTE: first tag is [1], not [0]
        pvno            [1] INTEGER (5) ,
        msg-type        [2] INTEGER (10 -- AS -- | 12 -- TGS --),
        padata          [3] SEQUENCE OF PA-DATA OPTIONAL
                            -- NOTE: not empty --,
        req-body        [4] KDC-REQ-BODY

}

KDC-REQ-BODY ::= SEQUENCE { kdc-options [0] KDCOptions, cname [1] PrincipalName OPTIONAL -- Used only in AS-REQ --, realm [2] Realm -- Server's realm -- Also client's in AS-REQ --, sname [3] PrincipalName OPTIONAL, from [4] KerberosTime OPTIONAL, till [5] KerberosTime, rtime [6] KerberosTime OPTIONAL, nonce [7] UInt32, etype [8] SEQUENCE OF Int32 -- EncryptionType -- in preference order --, addresses [9] HostAddresses OPTIONAL, enc-authorization-data [10] EncryptedData OPTIONAL -- AuthorizationData --, additional-tickets [11] SEQUENCE OF Ticket OPTIONAL -- NOTE: not empty }

KDCOptions ::= KerberosFlags -- reserved(0), -- forwardable(1), -- forwarded(2), -- proxiable(3), -- proxy(4), -- allow-postdate(5), -- postdated(6), -- unused7(7), -- renewable(8), -- unused9(9), -- unused10(10), -- opt-hardware-auth(11), -- unused12(12), -- unused13(13), -- 15 is reserved for canonicalize -- unused15(15), -- 26 was unused in 1510 -- disable-transited-check(26), -- -- renewable-ok(27), -- enc-tkt-in-skey(28), -- renew(30), -- validate(31)

Okay, let's break down the fields in this message, because each one has its own job ๐Ÿงšโœจ

pvno shows up in every single message ๐Ÿ’– It holds the protocol version number, and this spec is all about version 5.

msg-type tells you what kind of message you're looking at ๐Ÿฆ‹ It's almost always the same as the application identifier for the message. It's basically there so apps can grab it easily. For the KDC-REQ message, this type is going to be KRB_AS_REQ or KRB_TGS_REQ.

padata holds pre-authentication data, and it's giving main character energy ๐Ÿ‘‘ Requests for additional tickets (KRB_TGS_REQ) MUST contain a padata of PA-TGS-REQ. No skipping that one, bestie ๐Ÿ˜ญ

The padata (pre-authentication data) field is a list of auth info that might be needed before credentials can be issued or decrypted ๐Ÿ”

req-body is a placeholder that marks where the rest of the fields live ๐ŸŽ€ If you're calculating a checksum over the request, you do it over an encoding of the KDC-REQ-BODY sequence that's enclosed within req-body. โœจ

kdc-options shows up in the KRB_AS_REQ and KRB_TGS_REQ requests sent to the KDC ๐ŸŒธ It tells the KDC which flags the client wants set on its tickets, plus other info that changes how the KDC behaves. When an option has a name, that name can match the flag it sets. Usually the bit in the options field matches the bit in the flags field, but that's not guaranteed, so it's not acceptable to just copy the options field over to the flags field. Babe, no shortcuts ๐Ÿ™…โ€โ™€๏ธ There are also various checks that must be made before an option gets honored anyway.

The kdc_options field is a bit-field ๐Ÿ’œ Selected options get the bit set to 1, and unselected options and reserved fields get reset to 0. The encoding of the bits is in Section 5.2. The options are described in more detail above in Section 2. Here's the tea on what each one means:


Bits    Name                     Description

0       RESERVED                 Reserved for future expansion of
                                 this field.

1       FORWARDABLE              The FORWARDABLE option indicates
                                 that the ticket to be issued is to
                                 have its forwardable flag set.  It
                                 may only be set on the initial
                                 request, or in a subsequent request
                                 if the TGT on which it is based is
                                 also forwardable.

2       FORWARDED                The FORWARDED option is only
                                 specified in a request to the
                                 ticket-granting server and will only
                                 be honored if the TGT in the request
                                 has its FORWARDABLE bit set.  This
                                 option indicates that this is a
                                 request for forwarding.  The
                                 address(es) of the host from which
                                 the resulting ticket is to be valid
                                 are included in the addresses field
                                 of the request.

3       PROXIABLE                The PROXIABLE option indicates that
                                 the ticket to be issued is to have
                                 its proxiable flag set.  It may only
                                 be set on the initial request, or a
                                 subsequent request if the TGT on
                                 which it is based is also proxiable.

4       PROXY                    The PROXY option indicates that this
                                 is a request for a proxy.  This
                                 option will only be honored if the
                                 TGT in the request has its PROXIABLE
                                 bit set.  The address(es) of the
                                 host from which the resulting ticket
                                 is to be valid are included in the
                                 addresses field of the request.

5       ALLOW-POSTDATE           The ALLOW-POSTDATE option indicates
                                 that the ticket to be issued is to
                                 have its MAY-POSTDATE flag set.  It
                                 may only be set on the initial
                                 request, or in a subsequent request
                                 if the TGT on which it is based also
                                 has its MAY-POSTDATE flag set.

6       POSTDATED                The POSTDATED option indicates that
                                 this is a request for a postdated
                                 ticket.  This option will only be
                                 honored if the TGT on which it is
                                 based has its MAY-POSTDATE flag set.
                                 The resulting ticket will also have
                                 its INVALID flag set, and that flag
                                 may be reset by a subsequent request
                                 to the KDC after the starttime in
                                 the ticket has been reached.

7       RESERVED                 This option is presently unused.

8       RENEWABLE                The RENEWABLE option indicates that
                                 the ticket to be issued is to have
                                 its RENEWABLE flag set.  It may only
                                 be set on the initial request, or
                                 when the TGT on which the request is
                                 based is also renewable.  If this
                                 option is requested, then the rtime
                                 field in the request contains the
                                 desired absolute expiration time for
                                 the ticket.

9       RESERVED                 Reserved for PK-Cross.

10      RESERVED                 Reserved for future use.

11      RESERVED                 Reserved for opt-hardware-auth.

12-25   RESERVED                 Reserved for future use.

26      DISABLE-TRANSITED-CHECK  By default the KDC will check the
                                 transited field of a TGT against the
                                 policy of the local realm before it
                                 will issue derivative tickets based
                                 on the TGT.  If this flag is set in
                                 the request, checking of the
                                 transited field is disabled.
                                 Tickets issued without the
                                 performance of this check will be
                                 noted by the reset (0) value of the
                                 TRANSITED-POLICY-CHECKED flag,
                                 indicating to the application server
                                 that the transited field must be
                                 checked locally.  KDCs are
                                 encouraged but not required to honor
                                 the DISABLE-TRANSITED-CHECK option.

                                 This flag is new since RFC 1510.

27      RENEWABLE-OK             The RENEWABLE-OK option indicates
                                 that a renewable ticket will be
                                 acceptable if a ticket with the
                                 requested life cannot otherwise be
                                 provided, in which case a renewable
                                 ticket may be issued with a renew-
                                 till equal to the requested endtime.
                                 The value of the renew-till field
                                 may still be limited by local
                                 limits, or limits selected by the
                                 individual principal or server.

28      ENC-TKT-IN-SKEY          This option is used only by the
                                 ticket-granting service.  The ENC-
                                 TKT-IN-SKEY option indicates that
                                 the ticket for the end server is to
                                 be encrypted in the session key from
                                 the additional TGT provided.

29      RESERVED                 Reserved for future use.

30      RENEW                    This option is used only by the
                                 ticket-granting service.  The RENEW
                                 option indicates that the present
                                 request is for a renewal.  The
                                 ticket provided is encrypted in the
                                 secret key for the server on which
                                 it is valid.  This option will only
                                 be honored if the ticket to be
                                 renewed has its RENEWABLE flag set
                                 and if the time in its renew-till
                                 field has not passed.  The ticket to
                                 be renewed is passed in the padata
                                 field as part of the authentication
                                 header.
   31      VALIDATE                 This option is used only by the
                                    ticket-granting service.  The
                                    VALIDATE option indicates that the
                                    request is to validate a postdated
                                    ticket.  It will only be honored if
                                    the ticket presented is postdated,
                                    presently has its INVALID flag set,
                                    and would otherwise be usable at
                                    this time.  A ticket cannot be
                                    validated before its starttime.  The
                                    ticket presented for validation is
                                    encrypted in the key of the server
                                    for which it is valid and is passed
                                    in the padata field as part of the
                                    authentication header.

okay so bit 31 is VALIDATE ๐Ÿฆ‹ and it's giving "only for the ticket-granting service" energy ๐Ÿ’…. It's basically the request saying "hey, please check this postdated ticket for me." ๐ŸŽ€ It only gets honored if the ticket is postdated, has its INVALID flag set, and would otherwise be usable right now โœจ. And no validating a ticket before its starttime, bestie, that's a no-go ๐Ÿ™ˆ. The ticket you hand over is encrypted in the key of the server it's valid for, and it rides along in the padata field inside the authentication header ๐Ÿงš.

cname and sname: these work the same as the ones we went over for the ticket in Section 5.3 ๐Ÿ’œ. The sname can only be missing when the ENC-TKT-IN-SKEY option is on ๐ŸŒธ. If sname is absent, the server's name gets pulled from the client's name in the ticket you pass as additional-tickets ๐Ÿซถ.

enc-authorization-data: this one is only allowed in the TGS_REQ form ๐Ÿ‘‘. It's the authorization data you want, encrypted under the sub-session key if there's one in the Authenticator, or else under the session key from the TGT ๐Ÿ”. Both the Authenticator and the TGT come from the padata field in the KRB_TGS_REQ. The key usage value is 5 if you're using a sub-session key, or 4 if it's the session key ๐Ÿ”ฅ.

realm: this is the realm part of the server's principal identifier ๐ŸŒˆ. In the AS exchange, it's also the realm part of the client's principal identifier, so it does double duty ๐Ÿ’–.

from: included in the KRB_AS_REQ and KRB_TGS_REQ ticket requests when you want the ticket postdated โญ. It sets the desired starttime. If you leave it out, the KDC SHOULD use the current time instead ๐Ÿ“.

till: this is the expiration date the client is asking for ๐Ÿ’€. It's not optional, bestie! But if the requested endtime is "19700101000000Z", the client is asking for the maximum endtime that KDC policy allows ๐Ÿ‘‘. Fun fact from the implementation note: that special timestamp matches a UNIX time_t value of zero on most systems ๐Ÿค“โœจ.

rtime: the requested renew-till time, sent from client to KDC in a ticket request ๐Ÿฆ‹. It's optional, so no pressure ๐ŸŒธ.

nonce: this is part of both the KDC request and response ๐ŸŽ€. It's meant to hold a random number the client generated. If that same number shows up in the encrypted response from the KDC, it proves the response is fresh and hasn't been replayed by some attacker ๐Ÿ™ˆ. Nonces MUST NEVER be reused. Never, ever, ever ๐Ÿ˜ญ๐Ÿ”ฅ.

etype: this is the encryption algorithm you'd like used in the response ๐Ÿ’œ.

addresses: this shows up in the initial ticket request, and it's optional in requests for additional tickets from the ticket-granting server ๐Ÿงš. It lists the addresses where the requested ticket is valid. Normally that's the client's host addresses, but if a proxy is requested, this field holds other addresses instead ๐ŸŒˆ. The KDC usually copies these into the caddr field of the resulting ticket ๐Ÿ’….

additional-tickets: additional tickets MAY be included in a request to the ticket-granting server ๐Ÿซถ. If ENC-TKT-IN-SKEY is specified, then the session key from the additional ticket gets used in place of the server's key to encrypt the new ticket ๐Ÿ”. When ENC-TKT-IN-SKEY is used for user-to-user authentication, this additional ticket MAY be a TGT issued by the local realm, or an inter-realm TGT issued for the current KDC's realm by a remote KDC ๐Ÿ‘‘. If you ask for more than one option that needs additional tickets, they get used in the order set by the ordering of the options bits (see kdc-options, above) โœจ.

The application tag number is either ten (10) or twelve (12), depending on whether the request is for an initial ticket (AS-REQ) or for an additional ticket (TGS-REQ) ๐ŸŽ€.

The optional fields (addresses, authorization-data, and additional-tickets) only get included when they're actually needed to perform the operation specified in the kdc-options field ๐Ÿ’–.

Note that in KRB_TGS_REQ, the protocol version number shows up twice, and two different message types show up too ๐Ÿ™ˆ. The KRB_TGS_REQ message has these fields, and so does the authentication header (KRB_AP_REQ) that gets passed in the padata field ๐Ÿงš๐Ÿ’œ.

5.4.2. KRB_KDC_REP Definition ๐ŸŽ€

okay so the KRB_KDC_REP message is the reply the KDC sends back for either an initial (AS) request or a later (TGS) request ๐Ÿ’Œ. bestie, there's no message type literally called KRB_KDC_REP ๐Ÿ™ˆ. the type is either KRB_AS_REP or KRB_TGS_REP, and which one it is decides which key encrypts the ciphertext part of the reply ๐Ÿ”. for KRB_AS_REP, the ciphertext is encrypted in the client's secret key, and the client's key version number gets included in the key version number for the encrypted data โœจ. for KRB_TGS_REP, the ciphertext is encrypted in the sub-session key from the Authenticator. if that's absent, it's encrypted in the session key from the TGT used in the request ๐Ÿฆ‹. in that case, no version number will be present in the EncryptedData sequence ๐Ÿ’….

The KRB_KDC_REP message contains the following fields:

AS-REP          ::= [APPLICATION 11] KDC-REP

TGS-REP         ::= [APPLICATION 13] KDC-REP

KDC-REP         ::= SEQUENCE {
        pvno            [0] INTEGER (5),
        msg-type        [1] INTEGER (11 -- AS -- | 13 -- TGS --),
        padata          [2] SEQUENCE OF PA-DATA OPTIONAL
                                -- NOTE: not empty --,
        crealm          [3] Realm,
        cname           [4] PrincipalName,
        ticket          [5] Ticket,
        enc-part        [6] EncryptedData
                                -- EncASRepPart or EncTGSRepPart,
                                -- as appropriate
}

EncASRepPart    ::= [APPLICATION 25] EncKDCRepPart
EncTGSRepPart   ::= [APPLICATION 26] EncKDCRepPart

EncKDCRepPart   ::= SEQUENCE {
        key             [0] EncryptionKey,
        last-req        [1] LastReq,
        nonce           [2] UInt32,
        key-expiration  [3] KerberosTime OPTIONAL,
        flags           [4] TicketFlags,
        authtime        [5] KerberosTime,
        starttime       [6] KerberosTime OPTIONAL,
        endtime         [7] KerberosTime,
        renew-till      [8] KerberosTime OPTIONAL,
        srealm          [9] Realm,
        sname           [10] PrincipalName,
        caddr           [11] HostAddresses OPTIONAL
}

LastReq         ::=     SEQUENCE OF SEQUENCE {
        lr-type         [0] Int32,
        lr-value        [1] KerberosTime
}

pvno and msg-type ๐Ÿงพ These fields are described above in Section 5.4.1. msg-type is either KRB_AS_REP or KRB_TGS_REP.

padata ๐ŸŒธ This field is described in detail in Section 5.4.1. one possible use for it is encoding an alternate "salt" string to be used with a string-to-key algorithm. this is super useful for easing transitions if a realm name needs to change (like when a company gets acquired) ๐Ÿข. in that case, all existing password-derived entries in the KDC database would be flagged as needing a special salt string until the next password change ๐Ÿ”‘.

crealm, cname, srealm, and sname ๐Ÿ’œ These fields are the same as those described for the ticket in Section 5.3.

ticket ๐ŸŽŸ๏ธ The newly-issued ticket, from Section 5.3.

enc-part ๐Ÿซถ This field is a placeholder for the ciphertext and related information that forms the encrypted part of a message. the description of the encrypted part of the message follows each appearance of this field.

the key usage value for encrypting this field is 3 in an AS-REP message, using the client's long-term key or another key selected via pre-authentication mechanisms. in a TGS-REP message, the key usage value is 8 if the TGS session key is used, or 9 if a TGS authenticator subkey is used ๐Ÿ”ฅ.

Compatibility note: some implementations unconditionally send an encrypted EncTGSRepPart (application tag number 26) in this field, regardless of whether the reply is an AS-REP or a TGS-REP. for compatibility's sake, implementors MAY relax the check on the tag number of the decrypted ENC-PART ๐ŸŒˆ.

key ๐Ÿ—๏ธ This field is the same as described for the ticket in Section 5.3.

last-req โฐ This field is returned by the KDC and specifies the time(s) of the last request by a principal. depending on what info is available, this might be the last time a request for a TGT was made, or the last time a request based on a TGT was successful. it also might cover all servers for a realm, or just the particular server. some implementations MAY display this information to the user to help spot unauthorized use of one's identity ๐Ÿ‘€. it's kinda like the last login time you see when logging in to timesharing systems ๐Ÿ’€.

lr-type ๐Ÿฆ‹ This field indicates how the following lr-value field is to be interpreted. negative values mean the information pertains only to the responding server. non-negative values pertain to all servers for the realm ๐ŸŒ.

if the lr-type field is zero (0), then no information is conveyed by the lr-value subfield. if the absolute value of the lr-type field is one (1), then the lr-value subfield is the time of last initial request for a TGT. if it is two (2), then the lr-value subfield is the time of last initial request. if it is three (3), then the lr-value subfield is the time of issue for the newest TGT used. if it is four (4), then the lr-value subfield is the time of the last renewal. if it is five (5), then the lr-value subfield is the time of last request (of any type). if it is (6), then the lr-value subfield is the time when the password will expire. if it is (7), then the lr-value subfield is the time when the account will expire ๐Ÿง.

lr-value ๐ŸŽฏ This field contains the time of the last request. the time MUST be interpreted according to the contents of the accompanying lr-type subfield ๐Ÿ’–.

nonce ๐ŸŽฒ This field is described above in Section 5.4.1.

key-expiration ๐Ÿฅ€ The key-expiration field is part of the response from the KDC and specifies the time that the client's secret key is due to expire. the expiration might be the result of password aging or an account expiration. if present, it SHOULD be set to the earlier of the user's key expiration and account expiration. the use of this field is deprecated, and the last-req field SHOULD be used to convey this information instead ๐Ÿ“‰. this field will usually be left out of the TGS reply, since the response to the TGS request is encrypted in a session key and no client information has to be retrieved from the KDC database ๐Ÿ™…โ€โ™€๏ธ. it's up to the application client (usually the login program) to take appropriate action, like notifying the user, if the expiration time is imminent โš ๏ธ.

flags, authtime, starttime, endtime, renew-till and caddr ๐ŸŒŸ These fields are duplicates of those found in the encrypted portion of the attached ticket (see Section 5.3). they're provided so the client MAY verify that they match the intended request, and to help with proper ticket caching ๐Ÿง . if the message is of type KRB_TGS_REP, the caddr field will only be filled in if the request was for a proxy or forwarded ticket, or if the user is substituting a subset of the addresses from the TGT. if the client-requested addresses are not present or not used, then the addresses contained in the ticket will be the same as those included in the TGT ๐Ÿซง.


5.5. Client/Server (CS) Message Specifications ๐Ÿ’Œ

this section specifies the format of the messages used for the authentication of the client to the application server ๐Ÿ”โœจ.

5.5.1. KRB_AP_REQ Definition โœจ

okay bestie, the KRB_AP_REQ message is where the client walks up to the server with its ticket and basically says "it's me ๐Ÿ’…". It carries the Kerberos protocol version number, the message type KRB_AP_REQ, an options field for any options in use, and the ticket and authenticator themselves. People love calling this one the "authentication header" ๐ŸŽ€

AP-REQ          ::= [APPLICATION 14] SEQUENCE {
        pvno            [0] INTEGER (5),
        msg-type        [1] INTEGER (14),
        ap-options      [2] APOptions,
        ticket          [3] Ticket,
        authenticator   [4] EncryptedData -- Authenticator
}

APOptions       ::= KerberosFlags
        -- reserved(0),
        -- use-session-key(1),
        -- mutual-required(2)

pvno and msg-type ๐ŸŒธ These fields are the same ones we went over above in Section 5.4.1. msg-type is KRB_AP_REQ, so nothing fancy there.

ap-options ๐Ÿฆ‹ This field shows up in the application request (KRB_AP_REQ) and changes how the request gets processed. It's a bit-field, so a selected option is a bit set to 1, and anything unselected or reserved is reset to 0. The bit encoding lives in Section 5.2. Here's what each option means:

Bit(s)  Name             Description

0       reserved         Reserved for future expansion of this field.

1       use-session-key  The USE-SESSION-KEY option indicates that
                         the ticket the client is presenting to a
                         server is encrypted in the session key from
                         the server's TGT.  When this option is not
                         specified, the ticket is encrypted in the
                         server's secret key.

2       mutual-required  The MUTUAL-REQUIRED option tells the server
                         that the client requires mutual
                         authentication, and that it must respond
                         with a KRB_AP_REP message.

3-31    reserved         Reserved for future use.

ticket ๐ŸŽ€ This is the ticket that authenticates the client to the server. Main character energy โœจ

authenticator ๐Ÿ’– This carries the encrypted authenticator, which includes the client's choice of a subkey.

The encrypted authenticator rides along in the AP-REQ and proves to the server that the sender recently knew the encryption key inside the ticket, which helps the server catch replays ๐Ÿ•ต๏ธโ€โ™€๏ธ It also helps pick out the "true session key" for that particular session. The DER encoding of the following gets encrypted with the ticket's session key, using a key usage value of 11 in normal application exchanges, or 7 when it's used as the PA-TGS-REQ PA-DATA field of a TGS-REQ exchange (see Section 5.4.1):

-- Unencrypted authenticator
Authenticator   ::= [APPLICATION 2] SEQUENCE  {
        authenticator-vno       [0] INTEGER (5),
        crealm                  [1] Realm,
        cname                   [2] PrincipalName,
        cksum                   [3] Checksum OPTIONAL,
        cusec                   [4] Microseconds,
        ctime                   [5] KerberosTime,
        subkey                  [6] EncryptionKey OPTIONAL,
        seq-number              [7] UInt32 OPTIONAL,
        authorization-data      [8] AuthorizationData OPTIONAL
}

Here's the rundown on each field inside the authenticator ๐Ÿ‘‘

authenticator-vno ๐ŸŒˆ This field says which version of the authenticator format is being used. This document specifies version 5.

crealm and cname ๐Ÿงš These are the same as what we described for the ticket in Section 5.3.

cksum ๐Ÿ“ This is a checksum of the application data that comes along with the KRB_AP_REQ. It's computed with a key usage value of 10 in normal application exchanges, or 6 when it's used in the TGS-REQ PA-TGS-REQ AP-DATA field.

cusec โญ This is the microsecond part of the client's timestamp. Before encryption, its value runs from 0 to 999999. It usually shows up alongside ctime, and the two of them together give you a reasonably accurate timestamp.

ctime ๐ŸŒธ This is the current time on the client's host.

subkey ๐Ÿฆ‹ This is the client's pick for an encryption key to protect this one specific application session. Unless an application says otherwise, if this field gets left out, the session key from the ticket is used instead.

seq-number ๐Ÿ’œ This optional field holds the initial sequence number for KRB_PRIV or KRB_SAFE messages, for when sequence numbers are used to catch replays. (Application-specific messages can use it too.) When it's in the authenticator, it sets the initial sequence number for messages going from the client to the server. When it's in the AP-REP message, the initial sequence number is for messages going from the server to the client. In KRB_PRIV or KRB_SAFE messages, it goes up by one after each message gets sent. Sequence numbers run from 0 through 2^32 - 1, then wrap back to zero after 2^32 - 1.

For sequence numbers to catch replays properly, they SHOULD be non-repeating, even across connection boundaries. The initial sequence number SHOULD be random and spread evenly across the whole space of possible sequence numbers, so an attacker can't guess it and so it and the successive numbers don't end up repeating other sequences. If a series of KRB_PRIV or KRB_SAFE messages is going to produce more than 2^32 messages, rekeying SHOULD be performed before sequence numbers get reused with the same encryption key. ๐Ÿ˜ญ

Implmentation note: Historically, some implementations send signed twos-complement numbers for sequence numbers. For compatibility's sake, implementations MAY accept the equivalent negative number where a positive number greater than 2^31 - 1 is expected. ๐Ÿ™ˆ

Implementation note: Like we said before, some implementations leave out the optional sequence number when its value would be zero. Implementations MAY accept an omitted sequence number when they expect a value of zero, and they SHOULD NOT transmit an Authenticator with an initial sequence number of zero. ๐Ÿ’€

authorization-data ๐ŸŒˆ This is the same as what Section 5.3 describes for the ticket. It's optional, and it only shows up when you want extra restrictions on using the ticket, on top of the ones already in the ticket itself.


5.5.2. KRB_AP_REP Definition โœจ

The KRB_AP_REP message carries the Kerberos protocol version number, the message type, and an encrypted time-stamp. The server sends it back in response to a KRB_AP_REQ where the mutual authentication option was picked in the ap-options field. It's the server saying "yep, I'm legit too" ๐Ÿซถ

AP-REP          ::= [APPLICATION 15] SEQUENCE {
        pvno            [0] INTEGER (5),
        msg-type        [1] INTEGER (15),
        enc-part        [2] EncryptedData -- EncAPRepPart
}

EncAPRepPart    ::= [APPLICATION 27] SEQUENCE {
        ctime           [0] KerberosTime,
        cusec           [1] Microseconds,
        subkey          [2] EncryptionKey OPTIONAL,
        seq-number      [3] UInt32 OPTIONAL
}

The encoded EncAPRepPart gets encrypted with the shared session key from the ticket. The optional subkey field can be used in an application-arranged negotiation to pick a per-association session key ๐Ÿ”ฅ

pvno and msg-type ๐ŸŒธ These are described above in Section 5.4.1. msg-type is KRB_AP_REP.

enc-part ๐Ÿฆ‹ This is described above in Section 5.4.2. It's computed with a key usage value of 12.

ctime ๐ŸŒˆ This is the current time on the client's host.

cusec โญ This is the microsecond part of the client's timestamp.

subkey ๐Ÿ’œ This is an encryption key that's going to protect this specific application session. For how this field is used to negotiate a key, check out Section 3.2.6. Unless an application says otherwise, if this field gets left out, the sub-session key from the authenticator gets used. And if that's also left out, the session key from the ticket takes over ๐Ÿ‘‘

seq-number ๐Ÿ“ This field is described above in Section 5.3.2.


5.5.3. Error Message Reply โœจ

If something goes wrong while the server is processing the application request, a KRB_ERROR message gets sent back instead. The format of that error message is in Section 5.9.1 ๐Ÿ™…โ€โ™€๏ธ The cname and crealm fields MAY be left out if the server can't figure out their right values from the corresponding KRB_AP_REQ message. And if the authenticator was decipherable, the ctime and cusec fields will hold the values from it ๐Ÿงš


5.6. KRB_SAFE Message Specification ๐Ÿ”’

okay so this section is all about the KRB_SAFE message, which either side of an application (client or server) can use to send a tamper-proof message to its peer ๐Ÿ’– It assumes a session key has already been swapped, for example through the KRB_AP_REQ/KRB_AP_REP messages. Rule one: no session key, no KRB_SAFE, periodt ๐Ÿ’…

5.6.1. KRB_SAFE definition โœจ

okay so the KRB_SAFE message is giving "tamper-proof but not secret" ๐Ÿ”’ It carries the user data plus a collision-proof checksum, keyed with the last encryption key negotiated via subkeys, or with the session key if no negotiation happened. ๐Ÿ’…

KRB-SAFE        ::= [APPLICATION 20] SEQUENCE {
        pvno            [0] INTEGER (5),
        msg-type        [1] INTEGER (20),
        safe-body       [2] KRB-SAFE-BODY,
        cksum           [3] Checksum
}

KRB-SAFE-BODY   ::= SEQUENCE {
        user-data       [0] OCTET STRING,
        timestamp       [1] KerberosTime OPTIONAL,
        usec            [2] Microseconds OPTIONAL,
        seq-number      [3] UInt32 OPTIONAL,
        s-address       [4] HostAddress,
        r-address       [5] HostAddress OPTIONAL
}

pvno and msg-type ๐Ÿ“ These fields are described above in Section 5.4.1. msg-type is KRB_SAFE.

safe-body ๐ŸŽ€ This is a placeholder for the body of the KRB-SAFE message.

cksum ๐Ÿ” This field holds the checksum of the application data, computed with a key usage value of 15.

The checksum is computed over the encoding of the KRB-SAFE sequence. First, the cksum is set to a type zero, zero-length value, and the checksum is computed over the encoding of the KRB-SAFE sequence. Then the checksum is set to the result of that computation. Finally, the KRB-SAFE sequence is encoded again. This method, although different than the one specified in RFC 1510, corresponds to existing practice. ๐Ÿง โœจ

user-data ๐Ÿ’Œ This field is part of the KRB_SAFE and KRB_PRIV messages, and holds the application-specific data being passed from the sender to the recipient.

timestamp โฐ This field is part of the KRB_SAFE and KRB_PRIV messages. Its contents are the current time as known by the sender of the message. By checking the timestamp, the recipient can make sure the message was recently generated and is not a replay. no replays allowed bestie ๐Ÿ™…โ€โ™€๏ธ

usec โฑ๏ธ This field is part of the KRB_SAFE and KRB_PRIV headers. It holds the microsecond part of the timestamp.

seq-number ๐Ÿ”ข This field is described above in Section 5.3.2.

s-address ๐Ÿ“ค Sender's address.

This field specifies the address in use by the sender of the message.

r-address ๐Ÿ“ฅ This field specifies the address in use by the recipient of the message. It MAY be omitted for some uses (such as broadcast protocols), but the recipient MAY arbitrarily reject such messages. This field, along with s-address, can be used to help detect messages that have been incorrectly or maliciously delivered to the wrong recipient. this pair is literally the bouncer at the door ๐Ÿฆ‹


5.7. KRB_PRIV Message Specification ๐ŸŒธ

This section specifies the format of a message that either side (client or server) of an application can use to send a message to its peer securely and privately. ๐Ÿคซ It presumes that a session key has previously been exchanged, for example by using the KRB_AP_REQ/KRB_AP_REP messages.

5.7.1. KRB_PRIV Definition

The KRB_PRIV message contains user data encrypted in the Session Key. ๐Ÿ”’๐Ÿ’œ The message fields are as follows:

KRB-PRIV        ::= [APPLICATION 21] SEQUENCE {
        pvno            [0] INTEGER (5),
        msg-type        [1] INTEGER (21),
                        -- NOTE: there is no [2] tag
        enc-part        [3] EncryptedData -- EncKrbPrivPart
}

EncKrbPrivPart  ::= [APPLICATION 28] SEQUENCE {
        user-data       [0] OCTET STRING,
        timestamp       [1] KerberosTime OPTIONAL,
        usec            [2] Microseconds OPTIONAL,
        seq-number      [3] UInt32 OPTIONAL,
        s-address       [4] HostAddress -- sender's addr --,
        r-address       [5] HostAddress OPTIONAL -- recip's addr
}

pvno and msg-type ๐Ÿ“ These fields are described above in Section 5.4.1. msg-type is KRB_PRIV.

enc-part ๐Ÿซถ This field holds an encoding of the EncKrbPrivPart sequence, encrypted under the session key with a key usage value of 13. This encrypted encoding is used for the enc-part field of the KRB-PRIV message.

user-data, timestamp, usec, s-address, and r-address ๐Ÿ’… These fields are described above in Section 5.6.1.

seq-number ๐Ÿ”ข This field is described above in Section 5.3.2.


5.8. KRB_CRED Message Specification ๐Ÿงš

This section specifies the format of a message that can be used to send Kerberos credentials from one principal to another. ๐Ÿช„ It's presented here to encourage a common mechanism that applications can use when forwarding tickets or providing proxies to subordinate servers. It presumes that a session key has already been exchanged, perhaps by using the KRB_AP_REQ/KRB_AP_REP messages.

5.8.1. KRB_CRED Definition

The KRB_CRED message contains a sequence of tickets to be sent, plus the information needed to use them, including the session key from each. โœจ That information is encrypted under an encryption key that was previously exchanged or transferred alongside the KRB_CRED message. The message fields are as follows:

KRB-CRED        ::= [APPLICATION 22] SEQUENCE {
        pvno            [0] INTEGER (5),
        msg-type        [1] INTEGER (22),
        tickets         [2] SEQUENCE OF Ticket,
        enc-part        [3] EncryptedData -- EncKrbCredPart
}

EncKrbCredPart  ::= [APPLICATION 29] SEQUENCE {
        ticket-info     [0] SEQUENCE OF KrbCredInfo,
        nonce           [1] UInt32 OPTIONAL,
        timestamp       [2] KerberosTime OPTIONAL,
        usec            [3] Microseconds OPTIONAL,
        s-address       [4] HostAddress OPTIONAL,
        r-address       [5] HostAddress OPTIONAL
}

KrbCredInfo     ::= SEQUENCE {
        key             [0] EncryptionKey,
        prealm          [1] Realm OPTIONAL,
        pname           [2] PrincipalName OPTIONAL,
        flags           [3] TicketFlags OPTIONAL,
        authtime        [4] KerberosTime OPTIONAL,
        starttime       [5] KerberosTime OPTIONAL,
        endtime         [6] KerberosTime OPTIONAL,
        renew-till      [7] KerberosTime OPTIONAL,
        srealm          [8] Realm OPTIONAL,
        sname           [9] PrincipalName OPTIONAL,
        caddr           [10] HostAddresses OPTIONAL
}

pvno and msg-type ๐Ÿ“ These fields are described above in Section 5.4.1. msg-type is KRB_CRED.

tickets ๐ŸŽŸ๏ธ These are the tickets obtained from the KDC specifically for use by the intended recipient. Successive tickets are paired with the corresponding KrbCredInfo sequence from the enc-part of the KRB-CRED message.

enc-part ๐Ÿ” This field holds an encoding of the EncKrbCredPart sequence, encrypted under the session key shared by the sender and the intended recipient, with a key usage value of 14. This encrypted encoding is used for the enc-part field of the KRB-CRED message.

Implementation note: Implementations of certain applications, most notably certain implementations of the Kerberos GSS-API mechanism, do not separately encrypt the contents of the EncKrbCredPart of the KRB-CRED message when sending it. In the case of those GSS-API mechanisms, this is not a security vulnerability, as the entire KRB-CRED message is itself embedded in an encrypted message. phew, layers of encryption ๐Ÿ™ˆ

nonce ๐ŸŽฒ If practical, an application MAY require the inclusion of a nonce generated by the recipient of the message. If the same value is included as the nonce in the message, it provides evidence that the message is fresh and has not been replayed by an attacker. A nonce MUST NEVER be reused. ๐Ÿšซ nonces are one-and-done, no exceptions, periodt

timestamp and usec โฐ These fields specify the time that the KRB-CRED message was generated. The time is used to provide assurance that the message is fresh.

s-address and r-address ๐Ÿ“ These fields are described above in Section 5.6.1. They are used optionally to provide additional assurance of the integrity of the KRB-CRED message.

key ๐Ÿ—๏ธ This field exists in the corresponding ticket passed by the KRB-CRED message, and it's used to pass the session key from the sender to the intended recipient. The field's encoding is described in Section 5.2.9.

The following fields are optional. If present, they can be associated with the credentials in the remote ticket file. If left out, it is assumed that the recipient of the credentials already knows their values. ๐Ÿซง

prealm and pname ๐Ÿ‘‘ The name and realm of the delegated principal identity.

flags, authtime, starttime, endtime, renew-till, srealm, sname, and caddr ๐ŸŒˆ These fields contain the values of the corresponding fields from the ticket found in the ticket field. Descriptions of the fields are identical to the descriptions in the KDC-REP message.


5.9. Error Message Specification ๐Ÿ™ˆ

This section specifies the format for the KRB_ERROR message. The fields in the message are meant to return as much information as possible about an error. ๐Ÿงพ It's not expected that all the information the fields require will be available for every type of error. If the appropriate information isn't available when the message is composed, the corresponding field is left out of the message.

Heads up: because the KRB_ERROR message is not integrity protected, it's quite possible for an intruder to synthesize or modify it. ๐Ÿ˜ฑ That means the client SHOULD NOT use any fields in this message for security-critical purposes, such as setting a system clock or generating a fresh authenticator. The message can still be useful for advising a user on the reason for some failure. ๐Ÿ’€

5.9.1. KRB_ERROR Definition

Okay so the KRB_ERROR message is made of these fields, bestie ๐Ÿ’…

KRB-ERROR       ::= [APPLICATION 30] SEQUENCE {
        pvno            [0] INTEGER (5),
        msg-type        [1] INTEGER (30),
        ctime           [2] KerberosTime OPTIONAL,
        cusec           [3] Microseconds OPTIONAL,
        stime           [4] KerberosTime,
        susec           [5] Microseconds,
        error-code      [6] Int32,
        crealm          [7] Realm OPTIONAL,
        cname           [8] PrincipalName OPTIONAL,
        realm           [9] Realm -- service realm --,
        sname           [10] PrincipalName -- service name --,
        e-text          [11] KerberosString OPTIONAL,
        e-data          [12] OCTET STRING OPTIONAL
}

pvno and msg-type ๐ŸŽ€ These fields were already explained up in Section 5.4.1. msg-type is KRB_ERROR, so you know exactly what kind of message this is ๐Ÿฆ‹

ctime and cusec โฐ These were covered above in Section 5.5.2. If the entity making the error already knows these values (like when it's replying to a failed authentication service request, for example), they should be filled in on the KRB-ERROR. If the values aren't available, these fields can just be left out. No drama โœจ

stime ๐Ÿ•ฐ๏ธ This is the current time on the server, and it's of type KerberosTime.

susec ๐Ÿ”ฌ This is the microsecond part of the server's timestamp. It goes from 0 to 999999. It shows up right alongside stime, and the two work together to give you a reasonably accurate timestamp. Teamwork makes the dream work ๐Ÿซถ

error-code ๐Ÿšจ This holds the error code that Kerberos or the server returns when a request fails. To figure out what the number means, check the list of error codes in Section 7.5.9. Implementations are encouraged to support national language support when they display error messages, so people can read them in their own language ๐ŸŒ

crealm, and cname ๐Ÿ‘‘ These were described above in Section 5.3. When the entity making the error knows these values, they should be filled in on the KRB-ERROR. If they aren't known, the crealm and cname fields SHOULD be omitted.

realm and sname ๐ŸŒธ Same deal as before, these are described above in Section 5.3.

e-text ๐Ÿ“ This is extra text that helps explain the error code for the failed request. For example, it might include a principal name that turned out to be unknown. Context is everything, periodt ๐Ÿ’…

e-data ๐Ÿงš This is extra data about the error that the application can use to recover from it or handle it. If the errorcode is KDC_ERR_PREAUTH_REQUIRED, then the e-data field will hold an encoding of a sequence of padata fields. Each one matches an acceptable pre-authentication method and can optionally carry data for that method:

METHOD-DATA     ::= SEQUENCE OF PA-DATA

For error codes defined in this document other than KDC_ERR_PREAUTH_REQUIRED, the format and contents of the e-data field are implementation-defined. Same goes for future error codes: their e-data format and contents are implementation-defined unless something says otherwise. Whether it's defined by the implementation or by a future document, the e-data field MAY take the form of TYPED-DATA:

TYPED-DATA      ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
        data-type       [0] Int32,
        data-value      [1] OCTET STRING OPTIONAL
}

5.10. Application Tag Numbers

Okay here's the tea on the application class tag numbers, which are used by the various data types we've covered in this section ๐Ÿ“ The table below lists them all:

Tag Number(s)  Type Name      Comments

0                             unused

1              Ticket         PDU

2              Authenticator  non-PDU

3              EncTicketPart  non-PDU

4-9                           unused

10             AS-REQ         PDU

11             AS-REP         PDU

12             TGS-REQ        PDU

13             TGS-REP        PDU
14             AP-REQ         PDU

15             AP-REP         PDU

16             RESERVED16     TGT-REQ (for user-to-user)

17             RESERVED17     TGT-REP (for user-to-user)

18-19                         unused

20             KRB-SAFE       PDU

21             KRB-PRIV       PDU

22             KRB-CRED       PDU

23-24                         unused

25             EncASRepPart   non-PDU

26             EncTGSRepPart  non-PDU

27             EncApRepPart   non-PDU

28             EncKrbPrivPart non-PDU

29             EncKrbCredPart non-PDU

30             KRB-ERROR      PDU

The ASN.1 types marked above as "PDU" (Protocol Data Unit) are the only ASN.1 types intended as top-level types of the Kerberos protocol. They're also the only types that may be used as elements in another protocol that makes use of Kerberos. So PDUs are the main characters, and everything else is a supporting cast ๐Ÿ‘‘๐Ÿฆ‹


6. Naming Constraints โœจ

6.1. Realm Names

Realm names are encoded as GeneralStrings, and technically a realm can pick whatever name it wants ๐Ÿ™ˆ BUT interoperability across realm boundaries needs everyone to agree on how realm names get assigned and what info they imply. Otherwise it's chaos ๐Ÿ’€

To keep those conventions enforced, each realm MUST conform to the conventions itself. It MUST also require that any realms it shares inter-realm keys with also conform to the conventions, and require the same from its neighbors. Accountability vibes ๐Ÿซถ

Kerberos realm names are case sensitive. Realm names that differ only in the case of their characters are not equivalent, so ATHENA.MIT.EDU and athena.mit.edu are not the same realm, bestie ๐Ÿ˜ญ Right now there are three styles of realm names: domain, X500, and other. Here are examples of each:

domain:   ATHENA.MIT.EDU
  X500:   C=US/O=OSF
 other:   NAMETYPE:rest/of.name=without-restrictions

Domain style ๐ŸŒˆ Domain style realm names MUST look like domain names. They consist of components separated by periods (.), and they contain neither colons (:) nor slashes (/). Domain names themselves are case insensitive, but for realms to match, the case has to match too. When you're making a new realm name based on an internet domain name, it is recommended by convention that the characters be converted to uppercase.

X.500 style ๐ŸŒธ X.500 names contain an equals sign (=) and cannot contain a colon (:) before the equals sign. The realm names for X.500 names are string representations of the names, with components separated by slashes. Leading and trailing slashes are not included. Note that the slash separator matches Kerberos implementations based on RFC 1510, but it's different from the separator recommended in RFC 2253. Plot twist ๐ŸŽญ

Other style ๐Ÿงš Names that fall into the other category MUST begin with a prefix that contains no equals sign (=) or period (.). That prefix MUST be followed by a colon (:) and then the rest of the name. All prefixes except those beginning with used are expected. Presently none are assigned.

Reserved ๐Ÿ”’ The reserved category includes strings that don't fall into the first three categories. Every name in this category is reserved. It's unlikely that names will get assigned to this category unless there's a very strong argument for not using the 'other' category.

These rules guarantee there won't be any conflicts between the various name styles, which is honestly so iconic ๐Ÿ‘‘

The following additional constraints apply to assigning realm names in the domain and X.500 categories. Either the name of a realm for the domain or X.500 formats must be used by the organization that owns (the one it was assigned to) an Internet domain name or X.500 name. Or, if no such names are registered, authority to use a realm name MAY be derived from the authority of the parent realm. For example, if there's no domain name for E40.MIT.EDU, then the administrator of the MIT.EDU realm can authorize the creation of a realm with that name ๐Ÿฆ‹

This works because the organization the parent is assigned to is presumably the organization authorized to assign names to its children in the X.500 and domain name systems too. If the parent assigns a realm name without also registering it in the domain name or X.500 hierarchy, then it's the parent's responsibility to make sure that in the future there won't exist a name identical to the child's realm name unless it's assigned to the same entity as the realm name. Responsibility is giving main character energy ๐Ÿ’…โœจ

6.2. Principal Names โœจ

Okay so realm names had their rules, and principal names need the same kind of agreement ๐Ÿ’– Everybody has to be on the same page about what a principal name is actually saying. The name-type field is the bit that tells you what kind of info the name is carrying ๐ŸŽ€ Honestly it's a hint. The name-type SHOULD be treated only as a hint to interpreting the meaning of a name, and it doesn't count when you're checking if two names are equivalent ๐Ÿฆ‹ Two principal names that only differ in name-type are the same principal, no cap. The name type doesn't split up the namespace into separate little rooms ๐ŸŒธ Ignore the name type and no two names can be the same, so at least one of the components, or the realm, MUST be different. Here are the name types that are defined:

   Name Type       Value  Meaning

   NT-UNKNOWN        0    Name type not known
   NT-PRINCIPAL      1    Just the name of the principal as in DCE,
                            or for users
   NT-SRV-INST       2    Service and other unique instance (krbtgt)
   NT-SRV-HST        3    Service with host name as instance
                            (telnet, rcommands)
   NT-SRV-XHST       4    Service with host as remaining components
   NT-UID            5    Unique ID
   NT-X500-PRINCIPAL 6    Encoded X.509 Distinguished name [RFC2253]
   NT-SMTP-NAME      7    Name in form of SMTP email name
                            (e.g., user@example.com)
   NT-ENTERPRISE    10    Enterprise name - may be mapped to principal
                            name

When a name only tells you that it's unique at one particular time and nothing else, the name type PRINCIPAL SHOULD be used ๐Ÿ’… The principal name type SHOULD be used for users, and it might also show up for a unique server. If the name is a unique machine-generated ID that's guaranteed never to get reassigned, then UID SHOULD be used ๐Ÿงš (Note that reassigning names of any type is generally a bad idea, since stale entries might stick around in access control lists ๐Ÿ™ˆ)

If the first component of a name identifies a service, and the remaining components identify an instance of that service in a server-specified way, then SRV-INST SHOULD be used ๐Ÿ‘‘ The Kerberos ticket-granting service is a good example of this. Its first component is krbtgt, and its second component says which realm the ticket is valid for.

If the first component is a service and there's a single component after it that names the host the server runs on, then SRV-HST SHOULD be used ๐ŸŒˆ This one is mostly for Internet services like telnet and the Berkeley R commands. If the separate parts of the host name show up as successive components after the service name, then SRV-XHST SHOULD be used โœจ This might be used to identify servers on hosts with X.500 names, where the slash (/) could otherwise be ambiguous.

A name type of NT-X500-PRINCIPAL SHOULD be used when a name from an X.509 certificate gets translated into a Kerberos name ๐Ÿฆ‹ The encoding of the X.509 name as a Kerberos principal shall conform to the encoding rules specified in RFC 2253.

The SMTP name type lets a name look like an SMTP email name ๐Ÿ’œ That name, including an "@" and a domain name, gets used as the one component of the principal name.

A name type of UNKNOWN SHOULD be used when the form of the name isn't known ๐Ÿซถ When you're comparing names, a name of type UNKNOWN will match principals authenticated with names of any type. A principal authenticated with a name of type UNKNOWN, though, will only match other names of type UNKNOWN. Main character energy of "I'm not sure what I am," but it's still valid ๐Ÿ’€

Names of any type with an initial component of 'krbtgt' are reserved for the Kerberos ticket-granting service ๐Ÿ”ฅ See Section 7.3 for the form of such names.

6.2.1. Name of Server Principals ๐Ÿ“

The principal identifier for a server on a host is usually made of two parts ๐ŸŽ€ First, the realm of the KDC the server is registered with. Second, a two-component name of type NT-SRV-HST, if the host name is an Internet domain name, or a multi-component name of type NT-SRV-XHST, if the host name is in a form (like X.500) that allows slash (/) separators. The first component of that two- or multi-component name identifies the service, and the later components identify the host ๐ŸŒธ When the host name isn't case sensitive (like Internet domain names), the host name MUST be lowercase ๐Ÿ’… If the application protocol says so for services like telnet and the Berkeley R commands that run with system privileges, the first component MAY be the string 'host' instead of a service-specific identifier โœจ

7. Constants and Other Defined Values ๐Ÿ‘‘

7.1. Host Address Types ๐Ÿฆ‹

Negative values for the host address type are all reserved for local use. Non-negative values are all reserved for officially assigned type fields and interpretations ๐Ÿ’–

Internet (IPv4) Addresses

IPv4 addresses are 32-bit (4-octet) quantities, encoded in MSB order (most significant byte first) ๐ŸŒˆ The IPv4 loopback address SHOULD NOT appear in a Kerberos PDU. The type of IPv4 addresses is two (2) ๐Ÿงš

Internet (IPv6) Addresses

IPv6 addresses [RFC3513] are 128-bit (16-octet) quantities, encoded in MSB order (most significant byte first) ๐Ÿ’œ The following addresses MUST NOT appear in any Kerberos PDU:

  • the Unspecified Address
  • the Loopback Address
  • Link-Local addresses

This restriction covers the address fields of Kerberos PDUs, but not the address fields of packets that might carry those PDUs ๐Ÿ™ˆ It's needed because an address with non-global scope could let a message get accepted from a node that happens to share that address, even though it isn't the host the entity that added the restriction had in mind. Kinda dangerous, honestly ๐Ÿ˜ญ If the link-local address type does need to be used for communication, then the address restriction in tickets must not be used (i.e., addressless tickets must be used) ๐Ÿซถ

IPv4-mapped IPv6 addresses MUST be represented as addresses of type 2 ๐Ÿ”ฅ

DECnet Phase IV Addresses

DECnet Phase IV addresses are 16-bit addresses, encoded in LSB order. The type of DECnet Phase IV addresses is twelve (12) ๐Ÿ“

Netbios Addresses

Netbios addresses are 16-octet addresses that are typically made of 1 to 15 alphanumeric characters, padded with the US-ASCII SPC character (code 32) ๐ŸŒธ The 16th octet MUST be the US-ASCII NUL character (code 0). The type of Netbios addresses is twenty (20) ๐Ÿ’…

Directional Addresses

Including the sender address in KRB_SAFE and KRB_PRIV messages is kinda annoying in lots of environments, because addresses can get changed in transport by network address translators ๐Ÿ˜ฉ But if you take those addresses out, the messages might be open to a reflection attack, where a message gets reflected back to whoever originated it ๐Ÿ’€ The directional address type is the way to dodge both transport addresses and reflection attacks ๐Ÿฆ‹ Directional addresses are encoded as four-byte unsigned integers in network byte order. If the message is originated by the party that sent the original KRB_AP_REQ message, then an address of 0 SHOULD be used. If the message is originated by the party that KRB_AP_REQ was sent to, then the address 1 SHOULD be used. Applications with multiple parties can specify other addresses ๐Ÿงš

Directional addresses MUST only be used for the sender address field in the KRB_SAFE or KRB_PRIV messages. They MUST NOT be used as a ticket address or in a KRB_AP_REQ message ๐Ÿ™…โ€โ™€๏ธ This address type SHOULD only be used when the sending party knows that the receiving party supports it. That generally means directional addresses should only show up when the application protocol requires their support ๐Ÿ’œ Directional addresses are type (3) โœจ

7.2. KDC Messaging: IP Transports ๐ŸŒˆ

Kerberos has two IP transport mechanisms for communication between clients and servers: UDP/IP and TCP/IP ๐ŸŽ€

7.2.1. UDP/IP transport ๐Ÿ’–

Kerberos servers (KDCs) that support IP transports MUST accept UDP requests. They SHOULD listen for them on port 88 (decimal), unless they're specifically configured to listen on an alternative UDP port ๐Ÿซถ Alternate ports MAY be used when you're running multiple KDCs for multiple realms on the same host ๐Ÿ“

Kerberos clients that support IP transports SHOULD support sending UDP requests ๐Ÿฆ‹ Clients SHOULD use KDC discovery [7.2.3] to identify the IP address and port they'll send their request to ๐Ÿ”ฅ

When contacting a KDC for a KRB_KDC_REQ request using UDP/IP transport, the client shall send a UDP datagram containing only an encoding of the request to the KDC ๐ŸŒธ The KDC will respond with a reply datagram containing only an encoding of the reply message (either a KRB_ERROR or a KRB_KDC_REP) to the sending port at the sender's IP address. The response to a request made through UDP/IP transport MUST also use UDP/IP transport ๐Ÿ’… If the response can't be handled using UDP (for example, because it's too large), the KDC MUST return KRB_ERR_RESPONSE_TOO_BIG, which forces the client to retry the request using the TCP transport ๐Ÿ˜ญโœจ

7.2.2. TCP/IP Transport โœจ

okay so KDCs that support IP transports MUST accept TCP requests ๐Ÿ’– and SHOULD listen for them on port 88 (decimal), unless they've been specifically configured to use an alternate TCP port. alternate ports MAY be used when you're running multiple KDCs for multiple realms on the same host ๐Ÿงš

Clients MUST support sending TCP requests ๐Ÿซถ, but they MAY choose to try a request first over the UDP transport. Clients SHOULD use KDC discovery [7.2.3] to figure out the IP address and port they'll send their request to ๐Ÿฆ‹

ngl this implementation note is a whole vibe ๐Ÿ’€: some extensions to the Kerberos protocol just won't succeed if any client or KDC that doesn't support the TCP transport is involved. implementations of RFC 1510 weren't required to support TCP/IP transports at all ๐Ÿ™ˆ

When the KRB_KDC_REQ message is sent to the KDC over a TCP stream, the response (KRB_KDC_REP or KRB-ERROR message) MUST be returned to the client on the same TCP stream that was established for the request ๐ŸŽ€. the KDC MAY close the TCP stream after sending a response, but it MAY also leave the stream open for a reasonable period of time if it expects a follow-up. the KDC has to manage its TCP/IP connections carefully so nobody can pull a denial of service attack based on how many open TCP/IP connections there are ๐Ÿ˜ญ

The client MUST be prepared to have the stream closed by the KDC at any time after receiving a response ๐Ÿ’…. a stream closure SHOULD NOT be treated as a fatal error. instead, if multiple exchanges are required (like certain forms of pre-authentication), the client may need to set up a new connection when it's ready to send the next messages. a client MAY close the stream after receiving a response, and SHOULD close it if it doesn't expect to send follow-up messages ๐Ÿ‘‘

A client MAY send multiple requests before receiving responses ๐Ÿ“, though it must be ready to handle the connection being closed after the first response.

Each request (KRB_KDC_REQ) and response (KRB_KDC_REP or KRB-ERROR) sent over the TCP stream is preceded by the length of the request as 4 octets in network byte order. the high bit of the length is reserved for future expansion and MUST currently be set to zero. if a KDC that doesn't understand how to interpret a set high bit in the length encoding receives a request with the high order bit of the length set, it MUST return a KRB-ERROR message with the error KRB_ERR_FIELD_TOOLONG and MUST close the TCP stream. ๐Ÿ˜ญ that's a lot of MUSTs, babe

If multiple requests are sent over a single TCP connection and the KDC sends multiple responses, the KDC is not required to send the responses in the order of the corresponding requests. this can let some implementations send each response as soon as it's ready ๐Ÿ”ฅ, even if earlier requests are still being processed (like waiting on an external device or database). iconic, honestly ๐Ÿฆ‹

7.2.3. KDC Discovery on IP Networks

Kerberos client implementations MUST provide a means for the client to determine the location of the Kerberos Key Distribution Centers (KDCs). traditionally, implementations stored this configuration info in a file on each client machine ๐Ÿ“, but experience showed that method causes problems with out-of-date information and scaling, especially with cross-realm authentication ๐Ÿ˜ฉ. this section describes a method for using the Domain Name System [RFC1035] to store KDC location information ๐ŸŒ

7.2.3.1. DNS vs. Kerberos: Case Sensitivity of Realm Names

In Kerberos, realm names are case sensitive ๐Ÿ™ƒ. it's strongly encouraged that all realm names be all uppercase, but not every site got the memo. some use all lowercase names and others use mixed case. DNS, on the other hand, is case insensitive for queries. the realm names MYREALM, myrealm, and MyRealm are all different, but they resolve the same in the domain name system, so it's necessary that only one of the possible combinations of upper- and lowercase characters be used in realm names ๐Ÿ’œ

7.2.3.2. Specifying KDC Location Information with DNS SRV records

KDC location information is to be stored using the DNS SRV RR [RFC2782]. the format of this RR is as follows:

_Service._Proto.Realm TTL Class SRV Priority Weight Port Target

The Service name for Kerberos is always "kerberos".

The Proto can be either "udp" or "tcp". If these SRV records are to be used, both "udp" and "tcp" records MUST be specified for all KDC deployments ๐ŸŽ€

The Realm is the Kerberos realm that this record corresponds to. The realm MUST be a domain-style realm name โœจ

TTL, Class, SRV, Priority, Weight, and Target have the standard meaning as defined in RFC 2782.

As per RFC 2782, the Port number used for "_udp" and "_tcp" SRV records SHOULD be the value assigned to "kerberos" by the Internet Assigned Number Authority: 88 (decimal), unless the KDC is configured to listen on an alternate TCP port ๐Ÿฆ‹

Implementation note: many existing client implementations don't support KDC Discovery and are configured to send requests to the IANA assigned port (88 decimal), so it is strongly recommended that KDCs be configured to listen on that port ๐Ÿซถ

7.2.3.3. KDC Discovery for Domain Style Realm Names on IP Networks

These are DNS records for a Kerberos realm EXAMPLE.COM ๐Ÿงš It has two Kerberos servers, kdc1.example.com and kdc2.example.com. Queries should be directed to kdc1.example.com first, as per the specified priority. Weights are not used in these sample records.

  _kerberos._udp.EXAMPLE.COM.     IN   SRV   0 0 88 kdc1.example.com.
  _kerberos._udp.EXAMPLE.COM.     IN   SRV   1 0 88 kdc2.example.com.
  _kerberos._tcp.EXAMPLE.COM.     IN   SRV   0 0 88 kdc1.example.com.
  _kerberos._tcp.EXAMPLE.COM.     IN   SRV   1 0 88 kdc2.example.com.

7.3. Name of the TGS ๐Ÿ‘‘

The principal identifier of the ticket-granting service shall be composed of three parts: the realm of the KDC issuing the TGS ticket, and a two-part name of type NT-SRV-INST, with the first part "krbtgt" and the second part the name of the realm that will accept the TGT. For example, a TGT issued by the ATHENA.MIT.EDU realm to be used to get tickets from the ATHENA.MIT.EDU KDC has a principal identifier of "ATHENA.MIT.EDU" (realm), ("krbtgt", "ATHENA.MIT.EDU") (name). A TGT issued by the ATHENA.MIT.EDU realm to be used to get tickets from the MIT.EDU realm has a principal identifier of "ATHENA.MIT.EDU" (realm), ("krbtgt", "MIT.EDU") (name) ๐Ÿ“

7.4. OID Arc for KerberosV5 ๐ŸŒˆ

This OID MAY be used to identify Kerberos protocol messages encapsulated in other protocols. It also designates the OID arc for KerberosV5-related OIDs assigned by future IETF action.

Implementation note: RFC 1510 had an incorrect value (5) for "dod" in its OID ๐Ÿ™ˆ

id-krb5         OBJECT IDENTIFIER ::= {
        iso(1) identified-organization(3) dod(6) internet(1)
        security(5) kerberosV5(2)
}

Assignment of OIDs beneath the id-krb5 arc must be obtained by contacting the registrar for the id-krb5 arc, or its designee. At the time of the issuance of this RFC, such registrations can be obtained by contacting krb5-oid-registrar@mit.edu ๐Ÿ’…

7.5. Protocol Constants and Associated Values ๐Ÿ”ฅ

The following tables list constants used in the protocol and define their meanings. In the "specification" section, ranges are specified that limit the values of constants for which values are defined here. This allows implementations to make assumptions about the maximum values that will be received for these constants. Implementations receiving values outside the range specified in the "specification" section MAY reject the request, but they MUST recover cleanly. ๐Ÿซถ

7.5.1. Key Usage Numbers ๐Ÿ’–

The encryption and checksum specifications in [RFC3961] require as input a "key usage number", to alter the encryption key used in any specific message in order to make certain types of cryptographic attack more difficult. These are the key usage values assigned in this document ๐ŸŽ€

        1.  AS-REQ PA-ENC-TIMESTAMP padata timestamp, encrypted with
            the client key (Section 5.2.7.2)

        2.  AS-REP Ticket and TGS-REP Ticket (includes TGS session
            key or application session key), encrypted with the
            service key (Section 5.3)
        3.  AS-REP encrypted part (includes TGS session key or
            application session key), encrypted with the client key
            (Section 5.4.2)
        4.  TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with
            the TGS session key (Section 5.4.1)
        5.  TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with
            the TGS authenticator subkey (Section 5.4.1)
        6.  TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator cksum,
            keyed with the TGS session key (Section 5.5.1)
        7.  TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator (includes
            TGS authenticator subkey), encrypted with the TGS session
            key (Section 5.5.1)
        8.  TGS-REP encrypted part (includes application session
            key), encrypted with the TGS session key (Section 5.4.2)
        9.  TGS-REP encrypted part (includes application session
            key), encrypted with the TGS authenticator subkey
            (Section 5.4.2)
       10.  AP-REQ Authenticator cksum, keyed with the application
            session key (Section 5.5.1)
       11.  AP-REQ Authenticator (includes application authenticator
            subkey), encrypted with the application session key
            (Section 5.5.1)
       12.  AP-REP encrypted part (includes application session
            subkey), encrypted with the application session key
            (Section 5.5.2)
       13.  KRB-PRIV encrypted part, encrypted with a key chosen by
            the application (Section 5.7.1)
       14.  KRB-CRED encrypted part, encrypted with a key chosen by
            the application (Section 5.8.1)
       15.  KRB-SAFE cksum, keyed with a key chosen by the
            application (Section 5.6.1)
    16-18.  Reserved for future use in Kerberos and related
            protocols.
       19.  AD-KDC-ISSUED checksum (ad-checksum in 5.2.6.4)
    20-21.  Reserved for future use in Kerberos and related
            protocols.
    22-25.  Reserved for use in the Kerberos Version 5 GSS-API
            mechanisms [RFC4121].
   26-511.  Reserved for future use in Kerberos and related
            protocols.
  512-1023.  Reserved for uses internal to a Kerberos implementation.
      1024.  Encryption for application use in protocols that do not
            specify key usage values

      1025.  Checksums for application use in protocols that do not
            specify key usage values
  1026-2047.  Reserved for application use.

7.5.2. PreAuthentication Data Types โœจ

okay bestie, this is the padata menu ๐Ÿ“ every preauth data type gets its own number and a little label, and some of them come with notes like "deprecated" or who-wrote-it credits. no cap, the credits are so iconic ๐Ÿ’…

   Padata and Data Type    Padata-type   Comment
                            Value

   PA-TGS-REQ                  1
   PA-ENC-TIMESTAMP            2
   PA-PW-SALT                  3
   [reserved]                  4
   PA-ENC-UNIX-TIME            5        (deprecated)
   PA-SANDIA-SECUREID          6
   PA-SESAME                   7
   PA-OSF-DCE                  8
   PA-CYBERSAFE-SECUREID       9
   PA-AFS3-SALT                10
   PA-ETYPE-INFO               11
   PA-SAM-CHALLENGE            12       (sam/otp)
   PA-SAM-RESPONSE             13       (sam/otp)
   PA-PK-AS-REQ_OLD            14       (pkinit)
   PA-PK-AS-REP_OLD            15       (pkinit)
   PA-PK-AS-REQ                16       (pkinit)
   PA-PK-AS-REP                17       (pkinit)
   PA-ETYPE-INFO2              19       (replaces pa-etype-info)
   PA-USE-SPECIFIED-KVNO       20
   PA-SAM-REDIRECT             21       (sam/otp)
   PA-GET-FROM-TYPED-DATA      22       (embedded in typed data)
   TD-PADATA                   22       (embeds padata)
   PA-SAM-ETYPE-INFO           23       (sam/otp)
   PA-ALT-PRINC                24       (crawdad@fnal.gov)
   PA-SAM-CHALLENGE2           30       (kenh@pobox.com)
   PA-SAM-RESPONSE2            31       (kenh@pobox.com)
   PA-EXTRA-TGT                41       Reserved extra TGT
   TD-PKINIT-CMS-CERTIFICATES  101      CertificateSet from CMS
   TD-KRB-PRINCIPAL            102      PrincipalName
   TD-KRB-REALM                103      Realm
   TD-TRUSTED-CERTIFIERS       104      from PKINIT
   TD-CERTIFICATE-INDEX        105      from PKINIT
   TD-APP-DEFINED-ERROR        106      application specific
   TD-REQ-NONCE                107      INTEGER
   TD-REQ-SEQ                  108      INTEGER
   PA-PAC-REQUEST              128      (jbrezak@exchange.microsoft.com)

7.5.3. Address Types ๐ŸŒธ

the address type list is a lil roll call of network families, from IPv4 all the way to IPv6 ๐Ÿฆ‹ the numbers are the whole point here, so don't you dare fudge them ๐Ÿซถ

   Address Type                   Value

   IPv4                             2
   Directional                      3
   ChaosNet                         5
   XNS                              6
   ISO                              7
   DECNET Phase IV                 12
   AppleTalk DDP                   16
   NetBios                         20
   IPv6                            24

7.5.4. Authorization Data Types ๐Ÿ”ฅ

this one is giving full authorization drama ๐Ÿ‘‘ there's a numbered run of AD types, then a reserved range, then a few vendor-flavored ones with their credits. the reserved range is literally just "9-63" so yes, that's the whole vibe ๐Ÿ’€

   Authorization Data Type          Ad-type Value

   AD-IF-RELEVANT                     1
   AD-INTENDED-FOR-SERVER             2
   AD-INTENDED-FOR-APPLICATION-CLASS  3
   AD-KDC-ISSUED                      4
   AD-AND-OR                          5
   AD-MANDATORY-TICKET-EXTENSIONS     6
   AD-IN-TICKET-EXTENSIONS            7
   AD-MANDATORY-FOR-KDC               8
   Reserved values                 9-63
   OSF-DCE                           64
   SESAME                            65
   AD-OSF-DCE-PKI-CERTID             66 (hemsath@us.ibm.com)
   AD-WIN2K-PAC                     128 (jbrezak@exchange.microsoft.com)
   AD-ETYPE-NEGOTIATION             129  (lzhu@windows.microsoft.com)

7.5.5. Transited Encoding Types ๐Ÿงš

bestie, the transited encoding list is tiny but mighty โœจ one real type, and then everything else is reserved ๐Ÿ™ˆ

   Transited Encoding Type         Tr-type Value

   DOMAIN-X500-COMPRESS            1
   Reserved values                 All others

7.5.6. Protocol Version Number ๐Ÿ’œ

pvno is just 5 right now, and that's the current Kerberos protocol version number. one number, zero drama ๐ŸŽ€

   Label               Value   Meaning or MIT Code

   pvno                  5     Current Kerberos protocol version number

7.5.7. Kerberos Message Types ๐ŸŒˆ

okay this is the message type lineup and it's a whole vibe ๐Ÿ’… requests and responses come in pairs, there are a couple of reserved slots that are literally just waiting, and KRB_ERROR is the drama queen at 30 ๐Ÿ˜ญ

   Message Type   Value  Meaning

   KRB_AS_REQ      10    Request for initial authentication
   KRB_AS_REP      11    Response to KRB_AS_REQ request
   KRB_TGS_REQ     12    Request for authentication based on TGT
   KRB_TGS_REP     13    Response to KRB_TGS_REQ request
   KRB_AP_REQ      14    Application request to server
   KRB_AP_REP      15    Response to KRB_AP_REQ_MUTUAL
   KRB_RESERVED16  16    Reserved for user-to-user krb_tgt_request
   KRB_RESERVED17  17    Reserved for user-to-user krb_tgt_reply
   KRB_SAFE        20    Safe (checksummed) application message
   KRB_PRIV        21    Private (encrypted) application message
   KRB_CRED        22    Private (encrypted) message to forward
                           credentials
   KRB_ERROR       30    Error response

7.5.8. Name Types ๐Ÿฆ‹

last one in this part, and it's the name type gallery ๐Ÿ–ผ๏ธ from the unknown basic one to the enterprise name that can get mapped to a principal name. the X.500 one is literally pointing back to [RFC2253] so the citation stays put ๐Ÿซถ

   Name Type           Value  Meaning

   KRB_NT_UNKNOWN        0    Name type not known
   KRB_NT_PRINCIPAL      1    Just the name of the principal as in DCE,
                                or for users
   KRB_NT_SRV_INST       2    Service and other unique instance (krbtgt)
   KRB_NT_SRV_HST        3    Service with host name as instance
                                (telnet, rcommands)
   KRB_NT_SRV_XHST       4    Service with host as remaining components
   KRB_NT_UID            5    Unique ID
   KRB_NT_X500_PRINCIPAL 6    Encoded X.509 Distinguished name [RFC2253]
   KRB_NT_SMTP_NAME      7    Name in form of SMTP email name
                                (e.g., user@example.com)
   KRB_NT_ENTERPRISE    10    Enterprise name; may be mapped to
                                principal name

7.5.9. Error Codes

okay bestie, this is the error code table, and it's giving whole encyclopedia ๐Ÿ’€๐Ÿซถ every code has a number and a meaning, so when something breaks you can look up exactly what the KDC or the application server is complaining about. The table is copied exactly as it appears in the spec, with no changes to the codes, values, or meanings.

Error Code                         Value  Meaning

KDC_ERR_NONE                           0  No error
KDC_ERR_NAME_EXP                       1  Client's entry in database
                                            has expired
KDC_ERR_SERVICE_EXP                    2  Server's entry in database
                                            has expired
KDC_ERR_BAD_PVNO                       3  Requested protocol version
                                            number not supported

KDC_ERR_C_OLD_MAST_KVNO                4  Client's key encrypted in
                                            old master key
KDC_ERR_S_OLD_MAST_KVNO                5  Server's key encrypted in
                                            old master key
KDC_ERR_C_PRINCIPAL_UNKNOWN            6  Client not found in
                                            Kerberos database
KDC_ERR_S_PRINCIPAL_UNKNOWN            7  Server not found in
                                            Kerberos database
KDC_ERR_PRINCIPAL_NOT_UNIQUE           8  Multiple principal entries
                                            in database
KDC_ERR_NULL_KEY                       9  The client or server has a
                                            null key
KDC_ERR_CANNOT_POSTDATE               10  Ticket not eligible for
                                            postdating
KDC_ERR_NEVER_VALID                   11  Requested starttime is
                                            later than end time
KDC_ERR_POLICY                        12  KDC policy rejects request
KDC_ERR_BADOPTION                     13  KDC cannot accommodate
                                            requested option
KDC_ERR_ETYPE_NOSUPP                  14  KDC has no support for
                                            encryption type
KDC_ERR_SUMTYPE_NOSUPP                15  KDC has no support for
                                            checksum type
KDC_ERR_PADATA_TYPE_NOSUPP            16  KDC has no support for
                                            padata type
KDC_ERR_TRTYPE_NOSUPP                 17  KDC has no support for
                                            transited type
KDC_ERR_CLIENT_REVOKED                18  Clients credentials have
                                            been revoked
KDC_ERR_SERVICE_REVOKED               19  Credentials for server have
                                            been revoked
KDC_ERR_TGT_REVOKED                   20  TGT has been revoked
KDC_ERR_CLIENT_NOTYET                 21  Client not yet valid; try
                                            again later
KDC_ERR_SERVICE_NOTYET                22  Server not yet valid; try
                                            again later
KDC_ERR_KEY_EXPIRED                   23  Password has expired;
                                            change password to reset
KDC_ERR_PREAUTH_FAILED                24  Pre-authentication
                                            information was invalid
KDC_ERR_PREAUTH_REQUIRED              25  Additional pre-
                                            authentication required
KDC_ERR_SERVER_NOMATCH                26  Requested server and ticket
                                            don't match
KDC_ERR_MUST_USE_USER2USER            27  Server principal valid for
                                            user2user only
KDC_ERR_PATH_NOT_ACCEPTED             28  KDC Policy rejects
                                            transited path

KDC_ERR_SVC_UNAVAILABLE               29  A service is not available
KRB_AP_ERR_BAD_INTEGRITY              31  Integrity check on
                                            decrypted field failed
KRB_AP_ERR_TKT_EXPIRED                32  Ticket expired
KRB_AP_ERR_TKT_NYV                    33  Ticket not yet valid
KRB_AP_ERR_REPEAT                     34  Request is a replay
KRB_AP_ERR_NOT_US                     35  The ticket isn't for us
KRB_AP_ERR_BADMATCH                   36  Ticket and authenticator
                                            don't match
KRB_AP_ERR_SKEW                       37  Clock skew too great
KRB_AP_ERR_BADADDR                    38  Incorrect net address
KRB_AP_ERR_BADVERSION                 39  Protocol version mismatch
KRB_AP_ERR_MSG_TYPE                   40  Invalid msg type
KRB_AP_ERR_MODIFIED                   41  Message stream modified
KRB_AP_ERR_BADORDER                   42  Message out of order
KRB_AP_ERR_BADKEYVER                  44  Specified version of key is
                                            not available
KRB_AP_ERR_NOKEY                      45  Service key not available
KRB_AP_ERR_MUT_FAIL                   46  Mutual authentication
                                            failed
KRB_AP_ERR_BADDIRECTION               47  Incorrect message direction
KRB_AP_ERR_METHOD                     48  Alternative authentication
                                            method required
KRB_AP_ERR_BADSEQ                     49  Incorrect sequence number
                                            in message
KRB_AP_ERR_INAPP_CKSUM                50  Inappropriate type of
                                            checksum in message
KRB_AP_PATH_NOT_ACCEPTED              51  Policy rejects transited
                                            path
KRB_ERR_RESPONSE_TOO_BIG              52  Response too big for UDP;
                                            retry with TCP
KRB_ERR_GENERIC                       60  Generic error (description
                                            in e-text)
KRB_ERR_FIELD_TOOLONG                 61  Field is too long for this
                                            implementation
KDC_ERROR_CLIENT_NOT_TRUSTED          62  Reserved for PKINIT
KDC_ERROR_KDC_NOT_TRUSTED             63  Reserved for PKINIT
KDC_ERROR_INVALID_SIG                 64  Reserved for PKINIT
KDC_ERR_KEY_TOO_WEAK                  65  Reserved for PKINIT
KDC_ERR_CERTIFICATE_MISMATCH          66  Reserved for PKINIT
KRB_AP_ERR_NO_TGT                     67  No TGT available to
                                            validate USER-TO-USER
KDC_ERR_WRONG_REALM                   68  Reserved for future use
KRB_AP_ERR_USER_TO_USER_REQUIRED      69  Ticket must be for
                                            USER-TO-USER
KDC_ERR_CANT_VERIFY_CERTIFICATE       70  Reserved for PKINIT
KDC_ERR_INVALID_CERTIFICATE           71  Reserved for PKINIT
KDC_ERR_REVOKED_CERTIFICATE           72  Reserved for PKINIT
KDC_ERR_REVOCATION_STATUS_UNKNOWN     73  Reserved for PKINIT
KDC_ERR_REVOCATION_STATUS_UNAVAILABLE 74  Reserved for PKINIT
KDC_ERR_CLIENT_NAME_MISMATCH          75  Reserved for PKINIT
KDC_ERR_KDC_NAME_MISMATCH             76  Reserved for PKINIT

8. Interoperability Requirements โœจ

okay so Kerberos version 5 comes with SO many options ๐ŸŽ€ like, a ton. you've got multiple encryption and checksum types, alternative encoding schemes for the transited field, optional pre-authentication mechanisms, how to handle tickets with no addresses, options for mutual authentication, user-to-user authentication, proxies, the format of realm names, how authorization data gets handled, and forwarding, postdating, and renewing tickets. literally so much choice ๐Ÿ˜ญ

BUT if realms are gonna work together (interoperability, periodt ๐Ÿ’…), everyone needs to agree on a minimal configuration that every implementation supports. this baseline isn't set in stone tho, it can change as the tech changes ๐Ÿฆ‹ like, if one of the required encryption or checksum algorithms turns out to be insecure someday, it gets swapped out for something better. growth era fr ๐ŸŒฑ๐ŸŒˆ

8.1. Specification 2 ๐ŸŽ€

Okay so this section is where the second specification of these options gets defined ๐Ÿ’… Implementations set up this way can say they support Kerberos Version 5 Specification 2 (5.2). Specification 1 (deprecated) is over in RFC 1510, so go look there if you're curious ๐Ÿงš

Transport

TCP/IP and UDP/IP transport MUST be supported by clients and KDCs claiming conformance to specification 2. No cap, this one's a must ๐Ÿซถ

Encryption and Checksum Methods

The following encryption and checksum mechanisms MUST be supported:

  • Encryption: AES256-CTS-HMAC-SHA1-96 [RFC3962]
  • Checksums: HMAC-SHA1-96-AES256 [RFC3962]

Implementations SHOULD support other mechanisms as well, but the additional mechanisms may only be used when communicating with principals known to also support them. The following mechanisms from [RFC3961] and [RFC3962] SHOULD be supported:

  • Encryption: AES128-CTS-HMAC-SHA1-96, DES-CBC-MD5, DES3-CBC-SHA1-KD
  • Checksums: DES-MD5, HMAC-SHA1-DES3-KD, HMAC-SHA1-96-AES128

Implementations MAY support other mechanisms as well, but the additional mechanisms may only be used when communicating with principals known to support them also. ๐ŸŒˆ

Implementation note: Earlier implementations of Kerberos generate messages using the CRC-32 and RSA-MD5 checksum methods. For interoperability with these earlier releases, implementors MAY consider supporting these checksum methods but should carefully analyze the security implications to limit the situations within which these methods are accepted. ๐Ÿ’€ Careful with these ones, bestie!!

Realm Names

All implementations MUST understand hierarchical realms in both the Internet Domain and the X.500 style. When a TGT for an unknown realm is requested, the KDC MUST be able to determine the names of the intermediate realms between the KDCs realm and the requested realm. ๐Ÿฆ‹

Transited Field Encoding

DOMAIN-X500-COMPRESS (described in Section 3.3.3.2) MUST be supported. Alternative encodings MAY be supported, but they may only be used when that encoding is supported by ALL intermediate realms. โœจ

Pre-authentication Methods

The TGS-REQ method MUST be supported. It is not used on the initial request. The PA-ENC-TIMESTAMP method MUST be supported by clients, but whether it is enabled by default MAY be determined on a realm-by-realm basis. If the method is not used in the initial request and the error KDC_ERR_PREAUTH_REQUIRED is returned specifying PA-ENC-TIMESTAMP as an acceptable method, the client SHOULD retry the initial request using the PA-ENC-TIMESTAMP pre-authentication method. Servers need not support the PA-ENC-TIMESTAMP method, but if it is not supported the server SHOULD ignore the presence of PA-ENC-TIMESTAMP pre-authentication in a request. ๐Ÿ™ˆ

The ETYPE-INFO2 method MUST be supported; this method is used to communicate the set of supported encryption types, and corresponding salt and string to key parameters. The ETYPE-INFO method SHOULD be supported for interoperability with older implementation. ๐Ÿ“

Mutual Authentication

Mutual authentication (via the KRB_AP_REP message) MUST be supported. It's giving two-way trust, iconic ๐Ÿ‘‘

Ticket Addresses and Flags

All KDCs MUST pass through tickets that carry no addresses (i.e., if a TGT contains no addresses, the KDC will return derivative tickets). Implementations SHOULD default to requesting addressless tickets, as this significantly increases interoperability with network address translation. In some cases, realms or application servers MAY require that tickets have an address. ๐ŸŒธ

Implementations SHOULD accept directional address type for the KRB_SAFE and KRB_PRIV message and SHOULD include directional addresses in these messages when other address types are not available.

Proxies and forwarded tickets MUST be supported. Individual realms and application servers can set their own policy on when such tickets will be accepted. ๐Ÿซถ

All implementations MUST recognize renewable and postdated tickets, but they need not actually implement them. If these options are not supported, the starttime and endtime in the ticket SHALL specify a ticket's entire useful life. When a postdated ticket is decoded by a server, all implementations SHALL make the presence of the postdated flag visible to the calling server. โฐ

User-to-User Authentication

Support for user-to-user authentication (via the ENC-TKT-IN-SKEY KDC option) MUST be provided by implementations, but individual realms MAY decide as a matter of policy to reject such requests on a per-principal or realm-wide basis. ๐Ÿ’œ

Authorization Data

Implementations MUST pass all authorization data subfields from TGTs to any derivative tickets unless they are directed to suppress a subfield as part of the definition of that registered subfield type. (It is never incorrect to pass on a subfield, and no registered subfield types presently specify suppression at the KDC.)

Implementations MUST make the contents of any authorization data subfields available to the server when a ticket is used. Implementations are not required to allow clients to specify the contents of the authorization data fields. ๐Ÿ”ฅ

Constant Ranges

All protocol constants are constrained to 32-bit (signed) values unless further constrained by the protocol definition. This limit is provided to allow implementations to make assumptions about the maximum values that will be received for these constants. Implementations receiving values outside this range MAY reject the request, but they MUST recover cleanly. Bestie, the vibe is "handle the weird stuff gracefully" ๐Ÿงš

Following is a list of recommended values for a KDC configuration. Lowkey the cutest little table ever ๐Ÿ“

      Minimum lifetime              5 minutes
      Maximum renewable lifetime    1 week
      Maximum ticket lifetime       1 day
      Acceptable clock skew         5 minutes
      Empty addresses               Allowed
      Proxiable, etc.               Allowed

9. IANA Considerations ๐ŸŒˆ

Section 7 of this document specifies protocol constants and other defined values required for the interoperability of multiple implementations. Until a subsequent RFC specifies otherwise, or the Kerberos working group is shut down, allocations of additional protocol constants and other defined values required for extensions to the Kerberos protocol will be administered by the Kerberos working group. Following the recommendations outlined in [RFC2434], guidance is provided to the IANA as follows:

"reserved" realm name types in Section 6.1 and "other" realm types except those beginning with "X-" or "x-" will not be registered without IETF standards action, at which point guidelines for further assignment will be specified. Realm name types beginning with "X-" or "x-" are for private use. ๐Ÿ”’

For host address types described in Section 7.1, negative values are for private use. Assignment of additional positive numbers is subject to review by the Kerberos working group or other expert review.

Additional key usage numbers, as defined in Section 7.5.1, will be assigned subject to review by the Kerberos working group or other expert review.

Additional preauthentication data type values, as defined in section 7.5.2, will be assigned subject to review by the Kerberos working group or other expert review.

Additional authorization data types as defined in Section 7.5.4, will be assigned subject to review by the Kerberos working group or other expert review. Although it is anticipated that there may be significant demand for private use types, provision is intentionally not made for a private use portion of the namespace because conflicts between privately assigned values could have detrimental security implications. ๐Ÿ˜ญ Private-use drama is a real risk, so no private corner for these!

Additional transited encoding types, as defined in Section 7.5.5, present special concerns for interoperability with existing implementations. As such, such assignments will only be made by standards action, except that the Kerberos working group or another other working group with competent jurisdiction may make preliminary assignments for documents that are moving through the standards process. ๐Ÿงš

Additional Kerberos message types, as described in Section 7.5.7, will be assigned subject to review by the Kerberos working group or other expert review.

Additional name types, as described in Section 7.5.8, will be assigned subject to review by the Kerberos working group or other expert review.

Additional error codes described in Section 7.5.9 will be assigned subject to review by the Kerberos working group or other expert review. โœจ

10. Security Considerations ๐Ÿ”โœจ

okay bestie, this is the spicy section and I need you to actually read it ๐Ÿ˜ญ๐Ÿซถ Kerberos is an authentication service, so it helps verify who a principal is on the network. But by itself, it does not do authorization ๐Ÿ’…. Apps should not treat a service ticket from the Kerberos server as permission to use a service, because they can get bypassed when they interoperate with other KDCs or when other ways of authenticating the app exist ๐Ÿ™ˆ.

Denial of service is not solved by Kerberos ๐Ÿ’€. An intruder can stop an app from taking part in the proper authentication steps. Since authentication is required for lots of services, a successful DoS attack on a Kerberos server could take down other network services that rely on it. Kerberos is vulnerable to a few kinds of this: attacks on the network that stop clients from reaching the KDC, attacks on the domain name system that stop a client from finding the Kerberos server's IP address, and overloading the KDC with repeated requests.

Interoperability conflicts from incompatible character-set usage (see 5.2.1) can also cause denial of service for clients that use character sets in Kerberos strings other than the ones stored in the KDC database ๐ŸŒธ.

Authentication servers keep a database of principals (users and servers) and their secret keys, so the security of those machines is critical ๐Ÿšจ. If an authentication server gets breached, every server that relies on that KDC is compromised, and so is the authentication of every principal registered in that KDC's realm.

Principals have to keep their secret keys secret ๐Ÿคซ. If an intruder steals a principal's key, they can masquerade as that principal or impersonate any server to the legit principal.

Password-guessing attacks are also not solved by Kerberos ๐Ÿ™ƒ. If a user picks a weak password, an attacker can run an off-line dictionary attack, trying dictionary entries over and over to decrypt messages that are encrypted under a key derived from that password.

Unless pre-authentication is required by the policy of a realm, the KDC won't know whether an authentication request succeeds. An attacker can request a reply with credentials for any principal. Those credentials probably won't be much use unless the attacker knows the client's secret key, but the reply is encrypted in the client's secret key, which gives the attacker ciphertext to use for brute force or dictionary attacks against the user's password ๐Ÿ‘€. That's why it is strongly encouraged that Kerberos realms require pre-authentication. Even with pre-authentication, attackers may still try brute force or dictionary attacks against credentials they've observed by eavesdropping on the network.

A client can request a ticket for any server principal and then try a brute force or dictionary attack against that server principal's key using that ticket. So it is strongly encouraged that keys be randomly generated (rather than generated from passwords) for any principals that can be used as the target principal for a KRB_TGS_REQ or KRB_AS_REQ message ๐ŸŽฒ. [RFC4086]

The DES-CBC-MD5 encryption method and the DES-MD5 checksum method are listed as SHOULD be implemented for backward compatibility ๐Ÿ•ฐ๏ธ. But the single DES encryption algorithm they're based on is weak, so stronger algorithms should be used whenever possible ๐Ÿ’ช.

Each host on the network needs a clock that is loosely synchronized with the clocks of the other hosts โฐ. This synchronization reduces the bookkeeping application servers need to do for replay detection. The degree of "looseness" can be configured on a per-server basis, but it is typically on the order of 5 minutes. If clocks are synchronized over the network, the clock synchronization protocol MUST itself be secured from network attackers ๐Ÿ›ก๏ธ.

Principal identifiers must not be recycled on a short-term basis โ™ป๏ธ๐Ÿšซ. A typical access control setup uses access control lists (ACLs) to grant permissions to particular principals. If a stale ACL entry is left behind for a deleted principal and that principal identifier gets reused, the new principal will inherit the rights in the stale ACL entry ๐Ÿ˜ฑ. Not reusing principal identifiers removes the danger of accidental access.

Successfully decrypting a KRB_AS_REP message from the KDC is not enough for a host to verify the user's identity ๐Ÿ•ต๏ธ. The user and an attacker could work together to generate a KRB_AS_REP-format message that decrypts properly but isn't from the proper KDC. To authenticate a user logging on to a local system, the credentials obtained in the AS exchange may first be used in a TGS exchange to get credentials for a local server. Those credentials must then be verified by a local server through successful completion of the Client/Server exchange โœ….

Many RFC 1510-compliant implementations ignore unknown authorization data elements ๐Ÿ™„. Relying on those implementations to honor authorization data restrictions may create a security weakness.

Kerberos credentials contain clear-text information identifying the principals they apply to ๐Ÿ“. If privacy of this information is needed, the exchange itself should be wrapped in a protocol that provides confidentiality for the exchange of these credentials ๐Ÿ”’.

Applications must take care to protect communications after authentication ๐Ÿ’Œ. They can use the KRB_PRIV or KRB_SAFE messages as appropriate, or apply their own confidentiality or integrity mechanisms to those communications. Completing the KRB_AP_REQ and KRB_AP_REP exchange without later using confidentiality and integrity mechanisms only gives authentication of the parties to the communication, not confidentiality and integrity for what comes next. Applications that use confidentiality and integrity protection mechanisms other than KRB_PRIV and KRB_SAFE must make sure the authentication step is appropriately linked with the protected communication channel the application sets up ๐Ÿ”—.

Unless the application server has its own suitable way to protect against replay (for example, a challenge-response sequence the server starts after authentication, or a server-generated encryption subkey), the server must use a replay cache to remember any authenticator presented within the allowable clock skew ๐Ÿ“ผ. All services that share a key need to use the same replay cache. If separate replay caches are used, an authenticator used with one of those services could later be replayed to a different service with the same service principal ๐Ÿ˜ฌ.

If a server loses track of authenticators presented within the allowable clock skew, it must reject all requests until the clock skew interval has passed โณ. That way, any lost or replayed authenticators will fall outside the allowable clock skew and can't be successfully replayed anymore.

Implementations of Kerberos should not use untrusted directory servers to determine the realm of a host ๐Ÿ“‚๐Ÿšซ. Allowing that would let someone who compromises the directory server trick an attacker into directing the client to accept authentication with the wrong principal, one with a similar name but in a realm the legitimate host was never registered with ๐ŸŽญ.

Implementations of Kerberos must not use DNS to map one name to another (canonicalize) in order to determine the host part of the principal name you're about to talk to ๐ŸŒ๐Ÿšซ. Allowing that canonicalization would let a compromise of DNS cause a client to obtain credentials and authenticate correctly to the wrong principal. The client will know who it is communicating with, but it won't be the principal it intended to talk to ๐Ÿ˜ญ.

If the Kerberos server returns a TGT for a realm that is 'closer' than the desired realm, the client may use local policy configuration to verify that the authentication path used is an acceptable one ๐Ÿงญ. Alternatively, a client may choose its own authentication path rather than rely on the Kerberos server to pick one. Either way, any policy or configuration information used to choose or validate authentication paths, whether by the Kerberos server or the client, must come from a trusted source ๐Ÿ”.

The Kerberos protocol in its basic form does not provide perfect forward secrecy for communications ๐Ÿšจ. If an eavesdropper has recorded traffic, then messages encrypted using the KRB_PRIV message, or messages encrypted using application-specific encryption under keys exchanged using Kerberos, can be decrypted if the user's, application server's, or KDC's key is discovered later. This happens because the session key used to encrypt such messages is, when sent over the network, encrypted in the key of the application server. It is also encrypted under the session key from the user's TGT when it is returned to the user in the KRB_TGS_REP message. The session key from the TGT is sent to the user in the KRB_AS_REP message, encrypted in the user's secret key, and it is embedded in the TGT, which was encrypted in the key of the KDC. Applications that require perfect forward secrecy must exchange keys through mechanisms that provide that assurance, but they may still use Kerberos for authentication of the encrypted channel established through those other means ๐Ÿ’–.

11. Acknowledgements ๐Ÿซถ๐ŸŒท

This document is a revision of RFC 1510, which was co-authored with John Kohl ๐Ÿ’œ. The specification of the Kerberos protocol described here is the result of many years of effort ๐Ÿฅน. Over that time, lots of people contributed to defining the protocol and writing the specification. Sadly, it isn't possible to list every contributor as an author of this document, but there are many who aren't listed who are authors in spirit. That includes people who contributed text for parts of some sections, people who helped design parts of the protocol, and people who contributed significantly to the discussion of the protocol in the IETF common authentication technology (CAT) and Kerberos working groups ๐ŸŒˆ.

Among those who contributed to the development and specification of Kerberos were Jeffrey Altman, John Brezak, Marc Colan, Johan Danielsson, Don Davis, Doug Engert, Dan Geer, Paul Hill, John Kohl, Marc Horowitz, Matt Hur, Jeffrey Hutzelman, Paul Leach, John Linn, Ari Medvinsky, Sasha Medvinsky, Steve Miller, Jon Rochlis, Jerome Saltzer, Jeffrey Schiller, Jennifer Steiner, Ralph Swick, Mike Swift, Jonathan Trostle, Theodore Ts'o, Brian Tung, Jacques Vidrine, Assar Westerlund, and Nicolas Williams ๐Ÿ‘‘โœจ. Many other members of MIT Project Athena, the MIT networking group, and the Kerberos and CAT working groups of the IETF also contributed, but they aren't listed here ๐Ÿงš.


A. ASN.1 module ๐Ÿงฉ

KerberosV5Spec2 {
        iso(1) identified-organization(3) dod(6) internet(1)
        security(5) kerberosV5(2) modules(4) krb5spec2(2)

} DEFINITIONS EXPLICIT TAGS ::= BEGIN

-- OID arc for KerberosV5 -- -- This OID may be used to identify Kerberos protocol messages -- encapsulated in other protocols. -- -- This OID also designates the OID arc for KerberosV5-related OIDs. -- -- NOTE: RFC 1510 had an incorrect value (5) for "dod" in its OID. id-krb5 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) dod(6) internet(1) security(5) kerberosV5(2) }

Int32 ::= INTEGER (-2147483648..2147483647) -- signed values representable in 32 bits

UInt32 ::= INTEGER (0..4294967295) -- unsigned 32 bit values

Microseconds ::= INTEGER (0..999999) -- microseconds

KerberosString ::= GeneralString (IA5String)

Realm ::= KerberosString

PrincipalName ::= SEQUENCE { name-type [0] Int32, name-string [1] SEQUENCE OF KerberosString }

KerberosTime ::= GeneralizedTime -- with no fractional seconds

HostAddress ::= SEQUENCE { addr-type [0] Int32, address [1] OCTET STRING }

-- NOTE: HostAddresses is always used as an OPTIONAL field and -- should not be empty. HostAddresses -- NOTE: subtly different from rfc1510,

-- but has a value mapping and encodes the same ::= SEQUENCE OF HostAddress

-- NOTE: AuthorizationData is always used as an OPTIONAL field and -- should not be empty. AuthorizationData ::= SEQUENCE OF SEQUENCE { ad-type [0] Int32, ad-data [1] OCTET STRING }

PA-DATA ::= SEQUENCE { -- NOTE: first tag is [1], not [0] padata-type [1] Int32, padata-value [2] OCTET STRING -- might be encoded AP-REQ }

KerberosFlags ::= BIT STRING (SIZE (32..MAX)) -- minimum number of bits shall be sent, -- but no fewer than 32

EncryptedData ::= SEQUENCE { etype [0] Int32 -- EncryptionType --, kvno [1] UInt32 OPTIONAL, cipher [2] OCTET STRING -- ciphertext }

EncryptionKey ::= SEQUENCE { keytype [0] Int32 -- actually encryption type --, keyvalue [1] OCTET STRING }

Checksum ::= SEQUENCE { cksumtype [0] Int32, checksum [1] OCTET STRING }

Ticket ::= [APPLICATION 1] SEQUENCE { tkt-vno [0] INTEGER (5), realm [1] Realm, sname [2] PrincipalName, enc-part [3] EncryptedData -- EncTicketPart }

-- Encrypted part of ticket EncTicketPart ::= [APPLICATION 3] SEQUENCE { flags [0] TicketFlags, key [1] EncryptionKey, crealm [2] Realm, cname [3] PrincipalName, transited [4] TransitedEncoding, authtime [5] KerberosTime, starttime [6] KerberosTime OPTIONAL, endtime [7] KerberosTime, renew-till [8] KerberosTime OPTIONAL, caddr [9] HostAddresses OPTIONAL, authorization-data [10] AuthorizationData OPTIONAL }

-- encoded Transited field TransitedEncoding ::= SEQUENCE { tr-type [0] Int32 -- must be registered --, contents [1] OCTET STRING }

TicketFlags ::= KerberosFlags -- reserved(0), -- forwardable(1), -- forwarded(2), -- proxiable(3), -- proxy(4), -- may-postdate(5), -- postdated(6), -- invalid(7), -- renewable(8), -- initial(9), -- pre-authent(10), -- hw-authent(11), -- the following are new since 1510 -- transited-policy-checked(12), -- ok-as-delegate(13)

AS-REQ ::= [APPLICATION 10] KDC-REQ

TGS-REQ ::= [APPLICATION 12] KDC-REQ

KDC-REQ ::= SEQUENCE { -- NOTE: first tag is [1], not [0] pvno [1] INTEGER (5) , msg-type [2] INTEGER (10 -- AS -- | 12 -- TGS --), padata [3] SEQUENCE OF PA-DATA OPTIONAL -- NOTE: not empty --, req-body [4] KDC-REQ-BODY }

KDC-REQ-BODY ::= SEQUENCE { kdc-options [0] KDCOptions, cname [1] PrincipalName OPTIONAL -- Used only in AS-REQ --, realm [2] Realm -- Server's realm -- Also client's in AS-REQ --, sname [3] PrincipalName OPTIONAL, from [4] KerberosTime OPTIONAL, till [5] KerberosTime, rtime [6] KerberosTime OPTIONAL, nonce [7] UInt32, etype [8] SEQUENCE OF Int32 -- EncryptionType -- in preference order --, addresses [9] HostAddresses OPTIONAL, enc-authorization-data [10] EncryptedData OPTIONAL -- AuthorizationData --, additional-tickets [11] SEQUENCE OF Ticket OPTIONAL -- NOTE: not empty }

KDCOptions ::= KerberosFlags -- reserved(0), -- forwardable(1), -- forwarded(2), -- proxiable(3), -- proxy(4), -- allow-postdate(5), -- postdated(6), -- unused7(7), -- renewable(8), -- unused9(9), -- unused10(10), -- opt-hardware-auth(11), -- unused12(12), -- unused13(13), -- 15 is reserved for canonicalize -- unused15(15), -- 26 was unused in 1510 -- disable-transited-check(26), -- -- renewable-ok(27), -- enc-tkt-in-skey(28), -- renew(30), -- validate(31)

AS-REP ::= [APPLICATION 11] KDC-REP

TGS-REP ::= [APPLICATION 13] KDC-REP KDC-REP ::= SEQUENCE { pvno [0] INTEGER (5), msg-type [1] INTEGER (11 -- AS -- | 13 -- TGS --), padata [2] SEQUENCE OF PA-DATA OPTIONAL -- NOTE: not empty --, crealm [3] Realm, cname [4] PrincipalName, ticket [5] Ticket, enc-part [6] EncryptedData -- EncASRepPart or EncTGSRepPart, -- as appropriate }

EncASRepPart ::= [APPLICATION 25] EncKDCRepPart

EncTGSRepPart ::= [APPLICATION 26] EncKDCRepPart

EncKDCRepPart ::= SEQUENCE { key [0] EncryptionKey, last-req [1] LastReq, nonce [2] UInt32, key-expiration [3] KerberosTime OPTIONAL, flags [4] TicketFlags, authtime [5] KerberosTime, starttime [6] KerberosTime OPTIONAL, endtime [7] KerberosTime, renew-till [8] KerberosTime OPTIONAL, srealm [9] Realm, sname [10] PrincipalName, caddr [11] HostAddresses OPTIONAL }

LastReq ::= SEQUENCE OF SEQUENCE { lr-type [0] Int32, lr-value [1] KerberosTime }

AP-REQ ::= [APPLICATION 14] SEQUENCE { pvno [0] INTEGER (5), msg-type [1] INTEGER (14), ap-options [2] APOptions, ticket [3] Ticket, authenticator [4] EncryptedData -- Authenticator }

APOptions ::= KerberosFlags -- reserved(0), -- use-session-key(1), -- mutual-required(2)

-- Unencrypted authenticator Authenticator ::= [APPLICATION 2] SEQUENCE { authenticator-vno [0] INTEGER (5), crealm [1] Realm, cname [2] PrincipalName, cksum [3] Checksum OPTIONAL, cusec [4] Microseconds, ctime [5] KerberosTime, subkey [6] EncryptionKey OPTIONAL, seq-number [7] UInt32 OPTIONAL, authorization-data [8] AuthorizationData OPTIONAL }

AP-REP ::= [APPLICATION 15] SEQUENCE { pvno [0] INTEGER (5), msg-type [1] INTEGER (15), enc-part [2] EncryptedData -- EncAPRepPart }

EncAPRepPart ::= [APPLICATION 27] SEQUENCE { ctime [0] KerberosTime, cusec [1] Microseconds, subkey [2] EncryptionKey OPTIONAL, seq-number [3] UInt32 OPTIONAL }

KRB-SAFE ::= [APPLICATION 20] SEQUENCE { pvno [0] INTEGER (5), msg-type [1] INTEGER (20), safe-body [2] KRB-SAFE-BODY, cksum [3] Checksum }

KRB-SAFE-BODY ::= SEQUENCE { user-data [0] OCTET STRING, timestamp [1] KerberosTime OPTIONAL, usec [2] Microseconds OPTIONAL, seq-number [3] UInt32 OPTIONAL, s-address [4] HostAddress, r-address [5] HostAddress OPTIONAL }

KRB-PRIV ::= [APPLICATION 21] SEQUENCE { pvno [0] INTEGER (5), msg-type [1] INTEGER (21), -- NOTE: there is no [2] tag

enc-part [3] EncryptedData -- EncKrbPrivPart }

EncKrbPrivPart ::= [APPLICATION 28] SEQUENCE { user-data [0] OCTET STRING, timestamp [1] KerberosTime OPTIONAL, usec [2] Microseconds OPTIONAL, seq-number [3] UInt32 OPTIONAL, s-address [4] HostAddress -- sender's addr --, r-address [5] HostAddress OPTIONAL -- recip's addr }

KRB-CRED ::= [APPLICATION 22] SEQUENCE { pvno [0] INTEGER (5), msg-type [1] INTEGER (22), tickets [2] SEQUENCE OF Ticket, enc-part [3] EncryptedData -- EncKrbCredPart }

EncKrbCredPart ::= [APPLICATION 29] SEQUENCE { ticket-info [0] SEQUENCE OF KrbCredInfo, nonce [1] UInt32 OPTIONAL, timestamp [2] KerberosTime OPTIONAL, usec [3] Microseconds OPTIONAL, s-address [4] HostAddress OPTIONAL, r-address [5] HostAddress OPTIONAL }

KrbCredInfo ::= SEQUENCE { key [0] EncryptionKey, prealm [1] Realm OPTIONAL, pname [2] PrincipalName OPTIONAL, flags [3] TicketFlags OPTIONAL, authtime [4] KerberosTime OPTIONAL, starttime [5] KerberosTime OPTIONAL, endtime [6] KerberosTime OPTIONAL, renew-till [7] KerberosTime OPTIONAL, srealm [8] Realm OPTIONAL, sname [9] PrincipalName OPTIONAL, caddr [10] HostAddresses OPTIONAL }

KRB-ERROR ::= [APPLICATION 30] SEQUENCE { pvno [0] INTEGER (5), msg-type [1] INTEGER (30), ctime [2] KerberosTime OPTIONAL, cusec [3] Microseconds OPTIONAL, stime [4] KerberosTime, susec [5] Microseconds, error-code [6] Int32, crealm [7] Realm OPTIONAL, cname [8] PrincipalName OPTIONAL, realm [9] Realm -- service realm --, sname [10] PrincipalName -- service name --, e-text [11] KerberosString OPTIONAL, e-data [12] OCTET STRING OPTIONAL }

METHOD-DATA ::= SEQUENCE OF PA-DATA

TYPED-DATA ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { data-type [0] Int32, data-value [1] OCTET STRING OPTIONAL }

-- preauth stuff follows

PA-ENC-TIMESTAMP        ::= EncryptedData -- PA-ENC-TS-ENC

PA-ENC-TS-ENC           ::= SEQUENCE {
        patimestamp     [0] KerberosTime -- client's time --,
        pausec          [1] Microseconds OPTIONAL
}

ETYPE-INFO-ENTRY        ::= SEQUENCE {
        etype           [0] Int32,
        salt            [1] OCTET STRING OPTIONAL
}

ETYPE-INFO              ::= SEQUENCE OF ETYPE-INFO-ENTRY

ETYPE-INFO2-ENTRY       ::= SEQUENCE {
        etype           [0] Int32,
        salt            [1] KerberosString OPTIONAL,
        s2kparams       [2] OCTET STRING OPTIONAL
}

ETYPE-INFO2             ::= SEQUENCE SIZE (1..MAX) OF ETYPE-INFO2-ENTRY

AD-IF-RELEVANT          ::= AuthorizationData

AD-KDCIssued            ::= SEQUENCE {
        ad-checksum     [0] Checksum,
        i-realm         [1] Realm OPTIONAL,
        i-sname         [2] PrincipalName OPTIONAL,
        elements        [3] AuthorizationData

}

AD-AND-OR               ::= SEQUENCE {
        condition-count [0] Int32,
        elements        [1] AuthorizationData
}

AD-MANDATORY-FOR-KDC    ::= AuthorizationData

END

B. Changes since RFC 1510 ๐Ÿ’–

Okay, so this doc replaces RFC 1510 and finally clarifies the stuff that was never fully specified ๐Ÿซถ Anywhere the recommended implementation choices changed, or new options got added, those changes are described in the document and listed right here. The big glow-up is "Specification 2" in Section 8, which changes the required encryption and checksum methods so they match current best practices and deprecates the methods that aren't considered strong enough anymore ๐Ÿ”ฅ

Section 1 got a discussion about relying on the KDC to check the transited field, plus a flag in a ticket that says this check has happened. That's a brand-new capability that RFC 1510 didn't have โœจ Older implementations may ignore or not set this flag, and that doesn't bring any negative security implications, which is kind of iconic ๐Ÿ™ˆ

The definition of the secret key used to say that for a user, the key is derived from a password. RFC 1510 said the key was derived from the password. Now it's softer: for a user the key may be derived from a password ๐ŸŒธ This was done so things like a smart-card, or any other way of getting the user key without a password, actually fit ๐Ÿ’…

The introduction now mentions public key cryptography for initial authentication in Kerberos, by reference. RFC 1510 didn't have that reference at all ๐Ÿฆ‹

Section 1.3 is new, and it explains that even though Kerberos authenticates a named principal, it's still the application's job to make sure that the authenticated name is the actual entity it wants to talk to ๐Ÿ‘‘ Very main character of the app, honestly.

Discussion of extensibility was added to the introduction ๐Ÿงš

Discussion of how extensibility affects ticket flags and KDC options went into the introduction of Section 2 ๐Ÿ’œ No existing options or flags from RFC 1510 were changed. Some sections got renumbered, and text was revised so the existing options are clearer, especially the ENC-TKT-IN-SKEY option (now section 2.9.2), which is used for user-to-user authentication. The brand-new option and ticket flag, transited policy checking (Section 2.7), was added too โœจ

Section 3 got a warning about generating session keys for application use. It urges including key entropy from the KDC generated session key in the ticket ๐Ÿ”ฅ An example about using the sub-session key was added to Section 3.2.6 ๐ŸŽ€ Descriptions of the pa-etype-info, pa-etype-info2, and pa-pw-salt pre-authentication data items were added too. The recommendation for using pre-authentication changed from "MAY" to "SHOULD", and there's now a note about known plaintext attacks ๐Ÿ˜ญ

In RFC 1510, Section 4 described the database in the KDC. That discussion wasn't needed for interoperability and it unnecessarily boxed in implementations, so the old Section 4 is gone ๐Ÿ“

The current Section 4 used to be Section 6, all about encryption and checksum specifications ๐ŸŒˆ Most of that got updated to support new encryption methods and moved into a separate document. The few bits that are specific to Kerberos now live in Section 4 ๐Ÿงš

Section 5 got a major layout glow-up to make the correct behavior for optional fields clear ๐Ÿ’– A lot of this was necessary because the original Kerberos ASN.1 description was improper, and it left the correct behavior underspecified. The wording was also tightened wherever possible, so implementations that conform to this spec will stay extensible when new fields get added in future specs โœจ

Text was added about time_t=0 issues in the ASN.1 ๐Ÿ™ˆ There's also new text clarifying issues where implementations treat omitted optional integers as zero ๐Ÿซถ Behavior for optional SEQUENCE or SEQUENCE OF that may be empty got clarified too. Sequence numbers got a discussion covering how some implementations behave, including "zero" behavior and negative numbers ๐Ÿ”ฅ A compatibility note was added about always sending EncTGSRepPart no matter what the enclosing reply type is ๐Ÿ’… Minor changes were made to the HostAddresses description, and integer types got constrained. KerberosString is now defined as a (significantly) constrained GeneralString ๐Ÿ‘‘ KerberosFlags was defined to match existing implementation behavior that departs from RFC 1510's definition. The transited-policy-checked(12) and ok-as-delegate(13) ticket flags were added, and so was the disable-transited-check(26) KDC option ๐Ÿฆ‹

Descriptions of commonly implemented PA-DATA were added to Section 5 ๐ŸŒธ The KRB-SAFE description was updated to note the existing implementation behavior of double-encoding ๐Ÿงš

There used to be two definitions of METHOD-DATA in RFC 1510. The second one, meant for use with KRB_AP_ERR_METHOD, got removed, which leaves the SEQUENCE OF PA-DATA definition ๐Ÿ’œ

Section 7, naming constraints, moved from RFC 1510 into Section 6 โœจ

Words were added saying that domain-based realm names for newly created realms should be specified in uppercase. That recommendation doesn't make lowercase realm names illegal ๐Ÿ’– More words were added to point out that the slash-separated components in the X.500 style of realm names match existing RFC 1510 based implementations, but they conflict with the general X.500 name representation recommendation in RFC 2253 ๐Ÿ˜ญ

Section 8, network transport, constants and defined values, moved from RFC 1510 into Section 7 ๐ŸŽ€ Since RFC 1510, the TCP transport for Kerberos messages got defined, and the encryption and checksum number assignments moved into a separate document ๐ŸŒˆ

Again, "Specification 2" in Section 8 of the current document changes the required encryption and checksum methods to match the best current practices and deprecates the methods that are no longer considered sufficiently strong ๐Ÿ”ฅ

Two brand-new sections were added, one on IANA considerations and one on security considerations ๐Ÿซถ

The pseudo-code got removed from the appendix ๐Ÿ’€ It was sometimes misread as limiting implementation choices, and in RFC 1510 it wasn't always consistent with the words in the specification. So the effort went into clearing up ambiguities in the specification itself, instead of relying on the pseudo-code ๐Ÿ’…

An appendix was added with the complete ASN.1 module, drawn from the discussion in Section 5 of the current document ๐Ÿงš


END NOTES ๐ŸŒธ

(*TM) Project Athena, Athena, and Kerberos are trademarks of the Massachusetts Institute of Technology (MIT). ๐Ÿ’…

Normative References ๐Ÿฆ‹

  • [RFC3961] Raeburn, K., "Encryption and Checksum Specifications for Kerberos 5", RFC 3961, February 2005.
  • [RFC3962] Raeburn, K., "Advanced Encryption Standard (AES) Encryption for Kerberos 5", RFC 3962, February 2005.
  • [ISO-646/ECMA-6] International Organization for Standardization, "7-bit Coded Character Set for Information Interchange", ISO/IEC 646:1991.
  • [ISO-2022/ECMA-35] International Organization for Standardization, "Character code structure and extension techniques", ISO/IEC 2022:1994.
  • [RFC1035] Mockapetris, P., "Domain names - implementation and specification", STD 13, RFC 1035, November 1987.
  • [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
  • [RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 2434, October 1998.
  • [RFC2782] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.
  • [RFC2253] Wahl, M., Kille, S., and T. Howes, "Lightweight Directory Access Protocol (v3): UTF-8 String Representation of Distinguished Names", RFC 2253, December 1997.
  • [RFC3513] Hinden, R. and S. Deering, "Internet Protocol Version 6 (IPv6) Addressing Architecture", RFC 3513, April 2003.
  • [X680] Abstract Syntax Notation One (ASN.1): Specification of Basic Notation, ITU-T Recommendation X.680 (1997) | ISO/IEC International Standard 8824-1:1998.
  • [X690] ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER), ITU-T Recommendation X.690 (1997)| ISO/IEC International Standard 8825-1:1998.

Informative References

Okay, bestie, these are the receipts ๐Ÿงพโœจ Every paper and spec the RFC leans on, so you can go read the originals if you're curious.

  • [ISO-8859] International Organization for Standardization, "8-bit Single-byte Coded Graphic Character Sets -- Latin Alphabet", ISO/IEC 8859. ๐ŸŒธ
  • [RFC1964] Linn, J., "The Kerberos Version 5 GSS-API Mechanism", RFC 1964, June 1996. ๐Ÿ’œ
  • [DGT96] Don Davis, Daniel Geer, and Theodore Ts'o, "Kerberos With Clocks Adrift: History, Protocols, and Implementation", USENIX Computing Systems 9:1, January 1996. โฐ
  • [DS81] Dorothy E. Denning and Giovanni Maria Sacco, "Time-stamps in Key Distribution Protocols," Communications of the ACM, Vol. 24 (8), p. 533-536, August 1981. ๐Ÿ•ฐ๏ธ
  • [KNT94] John T. Kohl, B. Clifford Neuman, and Theodore Y. Ts'o, "The Evolution of the Kerberos Authentication System". In Distributed Open Systems, pages 78-94. IEEE Computer Society Press, 1994. ๐Ÿงš
  • [MNSS87] S. P. Miller, B. C. Neuman, J. I. Schiller, and J. H. Saltzer, Section E.2.1: Kerberos Authentication and Authorization System, M.I.T. Project Athena, Cambridge, Massachusetts, December 21, 1987. ๐Ÿ›๏ธ
  • [NS78] Roger M. Needham and Michael D. Schroeder, "Using Encryption for Authentication in Large Networks of Computers," Communications of the ACM, Vol. 21 (12), pp. 993-999, December 1978. ๐Ÿ”
  • [Neu93] B. Clifford Neuman, "Proxy-Based Authorization and Accounting for Distributed Systems," in Proceedings of the 13th International Conference on Distributed Computing Systems, Pittsburgh, PA, May 1993. ๐ŸŽ€
  • [NT94] B. Clifford Neuman and Theodore Y. Ts'o, "An Authentication Service for Computer Networks," IEEE Communications Magazine, Vol. 32 (9), p. 33-38, September 1994. ๐Ÿ“ก
  • [Pat92] J. Pato, Using Pre-Authentication to Avoid Password Guessing Attacks, Open Software Foundation DCE Request for Comments 26 (December 1992. ๐Ÿ™ˆ
  • [RFC1510] Kohl, J. and C. Neuman, "The Kerberos Network Authentication Service (V5)", RFC 1510, September 1993. ๐Ÿ‘‘
  • [RFC4086] Eastlake, D., 3rd, Schiller, J., and S. Crocker, "Randomness Requirements for Security", BCP 106, RFC 4086, June 2005. ๐ŸŽฒ
  • [SNS88] J. G. Steiner, B. C. Neuman, and J. I. Schiller, "Kerberos: An Authentication Service for Open Network Systems," p. 191-202, Usenix Conference Proceedings, Dallas, Texas, February 1988. ๐Ÿฆ‹
  • [RFC4121] Zhu, L., Jaganathan, K., and S. Hartman, "The Kerberos Version 5 Generic Security Service Application Program Interface (GSS-API) Mechanism: Version 2", RFC 4121, July 2005. โญ

Authors' Addresses โœจ

Meet the squad who built this thing ๐Ÿซถ Here's where you can find them:

Clifford Neuman
Information Sciences Institute
University of Southern California
4676 Admiralty Way
Marina del Rey, CA 90292, USA

EMail: bcn@isi.edu
Tom Yu
Massachusetts Institute of Technology
77 Massachusetts Avenue
Cambridge, MA 02139, USA

EMail: tlyu@mit.edu
Sam Hartman
Massachusetts Institute of Technology
77 Massachusetts Avenue
Cambridge, MA 02139, USA

EMail: hartmans-ietf@mit.edu
Kenneth Raeburn
Massachusetts Institute of Technology
77 Massachusetts Avenue
Cambridge, MA 02139, USA

EMail: raeburn@mit.edu

Copyright (C) The Internet Society (2005).

This document is covered by the rights, licenses, and restrictions in BCP 78. Except as BCP 78 says otherwise, the authors keep all their rights. ๐Ÿ“œ

The legal bit, verbatim because it matters ๐Ÿ˜ญ:

This document and the information contained herein are provided on an
"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
No warranties, no vibes-based guarantees. Read it as-is, bestie. ๐Ÿ™ˆ

Intellectual Property ๐Ÿ”ฅ

The IETF doesn't pick a side on whether any IPR (Intellectual Property Rights) or other rights might cover the tech in this doc. It also doesn't say whether you can get a license for it, and it hasn't done its own hunt for those rights either ๐Ÿ•ต๏ธโ€โ™€๏ธ For the rules on RFC rights, check BCP 78 and BCP 79.

Got IPR disclosures or license assurances? Those live with the IETF Secretariat, and you can find them in the IETF online IPR repository at http://www.ietf.org/ipr. The same goes for any attempt to get a general license or permission for implementers or users. ๐Ÿ—‚๏ธ

If you think you've got a copyright, patent, patent application, or other proprietary right that covers tech this standard might need, tell the IETF! Send it to ietf-ipr@ietf.org. Be the helpful one ๐Ÿซถ


Acknowledgement ๐ŸŒˆ

Funding for the RFC Editor function is currently provided by the Internet Society. Thank you, Internet Society ๐Ÿ’œโœจ

That's a wrap on RFC 4120, bestie!! ๐ŸŽ€๐Ÿฆ‹๐Ÿ‘‘

๐Ÿ“ฆ where this page comes from