RFC 2695

Authentication Mechanisms for ONC RPC

๐Ÿ“… published September 1999, from ietf

RFC 2695: Authentication Mechanisms for ONC RPC ๐ŸŽ€

Author: A. Chiu of Sun Microsystems ๐Ÿ’œ Category: Informational ๐ŸŒธ Date: September 1999 โœจ Obsoletes/Updates: the title block doesn't list any RFCs as obsoleted or updated ๐Ÿฆ‹


Status of This Memo ๐Ÿ“œ

okay so this memo is just information for the Internet community ๐Ÿ’… It does not specify an Internet standard of any kind, so it's not a standard, bestie. Distribution of this memo is unlimited, so share it with everyone ๐Ÿซถ

Copyright (C) The Internet Society (1999). All Rights Reserved. ๐Ÿ”’

Abstract ๐Ÿ’–

this doc describes two authentication mechanisms made by Sun Microsystems that get used a lot with the ONC Remote Procedure Call (ONC RPC Version 2) protocol ๐Ÿงš

WARNING ๐Ÿšจ

ok this part is SERIOUS bestie ๐Ÿ˜ญ The DH authentication in Section 2 is the one with flavor AUTH_DH that's currently in ONC RPC. It uses the Diffie-Hellman algorithm for key exchange. The DH authentication defined here is flawed because it picks a small prime for the BASE field (Section 2.5) ๐Ÿ’€ To dodge the flaw, a new DH authentication mechanism could be defined with a larger prime. BUT the new one wouldn't be interoperable with the existing DH authentication, so it's not a free fix ๐Ÿ˜ฉ
also, [10] shows that a LOT of attacks are possible on ONC RPC system services that use non-secure authentication mechanisms ๐Ÿ™ˆ Other secure authentication mechanisms need to be developed for ONC RPC, like, yesterday.

RFC 2203 describes the RPCSEC_GSS ONC RPC security flavor ๐Ÿ‘‘ It's a secure authentication mechanism that lets RPC protocols use the Generic Security Service Application Program Interface (RFC 2078) to get security services, integrity and privacy, and it works no matter what the underlying security mechanism is โœจ

Table of Contents ๐Ÿงพ

   1. Introduction ............................................... 2
   2. Diffie-Hellman Authentication .............................. 2
   2.1 Naming .................................................... 3
   2.2 DH Authentication Verifiers ............................... 3
   2.3 Nicknames and Clock Synchronization ....................... 5
   2.4 DH Authentication Protocol Specification .................. 5
   2.4.1 The Full Network Name Credential and Verifier (Client) .. 6
   2.4.2 The Nickname Credential and Verifier (Client) ........... 8
   2.4.3 The Nickname Verifier (Server) .......................... 9
   2.5 Diffie-Hellman Encryption ................................. 9
   3. Kerberos-based Authentication ............................. 10
   3.1 Naming ................................................... 11
   3.2 Kerberos-based Authentication Protocol Specification ..... 11
   3.2.1 The Full Network Name Credential and Verifier (Client) . 12
   3.2.2 The Nickname Credential and Verifier (Client) .......... 14
   3.2.3 The Nickname Verifier (Server) ......................... 15
   3.2.4 Kerberos-specific Authentication Status Values ......... 15
   4. Security Considerations ................................... 16
   5. REFERENCES ................................................ 16
   6. AUTHOR'S ADDRESS .......................................... 17
   7. FULL COPYRIGHT STATEMENT ...................................18

1. Introduction ๐ŸŒˆ

okay so the ONC RPC protocol gives you the fields a client needs to identify itself to a service, and the other way around too ๐Ÿซถ These fields show up in every call and reply message! Security and access control can get built on top of this message authentication, and several different authentication protocols can be supported ๐Ÿ’…

this doc specifies two authentication protocols that Sun Microsystems made and that people use a lot: Diffie-Hellman (DH) authentication and Kerberos (Version 4) based authentication ๐Ÿฆ‹

bestie, before you read this, you're expected to already know [1] and [2] ๐Ÿ“š This document uses terminology and definitions from [1] and [2], so go check those first, no cap ๐Ÿค“

2. Diffie-Hellman Authentication ๐Ÿ”

ngl system authentication (defined in [1]) has some problems ๐Ÿ˜ฉ It's very UNIX oriented, and it can be super easily faked, because there's no attempt at cryptographically secure authentication ๐Ÿ’€

DH authentication was made to fix these problems! BUT ๐Ÿฅบ it's been compromised [9] because the ONC RPC implementation picked a small length for the prime. The info here will be useful for implementors who want to stay interoperable with existing apps that use DH authentication, and it is strongly recommended that new applications use more secure authentication ๐Ÿ’– Existing apps that use DH authentication should migrate to more robust authentication mechanisms, periodt โœจ

2.1 Naming ๐Ÿท๏ธ

the client gets addressed by a simple string of characters instead of an operating system specific integer ๐Ÿงš This string is called the "netname" (or network name) of the client. The server isn't allowed to interpret the contents of the client's name in any other way except to identify the client ๐Ÿซถ So netnames should be unique for every client on the Internet, obviously!

it's up to each operating system's DH authentication implementation to generate netnames for its users that make sure they stay unique when they call remote servers ๐ŸŒธ Operating systems already know how to tell apart users that are local to their system, so it's usually a simple matter to extend that to the network ๐Ÿ’…

for example, a UNIX(tm) user at Sun with user ID 515 might get the netname "unix.515@sun.com" ๐ŸŽ€ This netname has three items that keep it unique. Going backwards: there's only one naming domain called "sun.com" on the Internet. Within that domain, there's only one UNIX(tm) user with user ID 515. BUT ๐Ÿ˜ญ there could be another user on another OS, like VMS, in the same naming domain who just happens to have user ID 515 too. To keep those two people distinguishable, we add the operating system name. So one user is "unix.515@sun.com" and the other is "vms.515@sun.com" ๐Ÿฆ‹

the first field is actually a naming method, not an operating system name ๐Ÿค“ It just happens that today there's almost a one-to-one match between naming methods and operating systems. If the world could agree on one naming standard, the first field could be the name of that standard instead of an OS name ๐ŸŒˆ

2.2 DH Authentication Verifiers โœ…

unlike System authentication, DH authentication does have a verifier, so the server can validate the client's credential (and the other way around too) ๐Ÿ’– The verifier's contents are mainly an encrypted timestamp. The server decrypts it, and if it's within an accepted range relative to the current time, then the client must have encrypted it correctly ๐Ÿ˜ค The only way the client could've encrypted it correctly is by knowing the "conversation key" of the RPC session, and if the client knows the conversation key, then it's gotta be the real client ๐Ÿ‘‘

the conversation key is a DES [5] key ๐Ÿ”‘ The client generates it and passes it to the server in the first RPC call of a session. The conversation key is encrypted using a public key scheme in that first transaction. The particular public key scheme used in DH authentication is Diffie-Hellman [3] with 192-bit keys ๐Ÿงš The details of this encryption method are described later.

the client and the server need the same notion of the current time for all of this to work ๐Ÿ•ฐ๏ธ That could come from something like the Network Time Protocol [4]. If network time synchronization can't be guaranteed, then the client can figure out the server's time before starting the conversation, using a time request protocol ๐ŸŒธ

how the server decides whether a client timestamp is valid is kinda complicated, not gonna lie ๐Ÿ˜ญ For any transaction except the first one, the server just checks two things:

(1) the timestamp is greater than the one previously seen from the same client. (2) the timestamp has not expired.

a timestamp is expired if the server's time is later than the sum of the client's timestamp plus the client's "ttl" (short for "time-to-live", think of it as the lifetime of the client's credential) โณ The "ttl" is a number the client passes (encrypted) to the server in its first transaction ๐Ÿ”

in the first transaction, the server only checks that the timestamp has not expired ๐Ÿ™ˆ As an extra check, the client also sends an encrypted item called the "ttl verifier" in that first transaction. It has to be equal to the time-to-live minus 1, or the server rejects the credential ๐Ÿ’… If either check fails, the server rejects the credential with an authentication status of AUTH_BADCRED. HOWEVER ๐Ÿ˜ณ if the timestamp is earlier than the previous one seen, the server returns an authentication status of AUTH_REJECTEDCRED instead.

the client has to check the verifier that comes back from the server too, to make sure it's legit ๐Ÿ•ต๏ธ The server sends back the timestamp it received from the client, minus one second, encrypted with the conversation key. If the client gets anything different from that, it rejects it and returns an AUTH_INVALIDRESP authentication status to the user. Not vibing with that response at all ๐Ÿ’€

2.3 Nicknames and Clock Synchronization โฐ

after the first transaction, the server's DH authentication subsystem sends back an integer "nickname" in its verifier to the client ๐ŸŽ€ The client can use this nickname in its later transactions instead of passing its netname every time. The nickname could be an index into a table on the server that stores each client's netname, decrypted conversation key, and ttl ๐Ÿ“‹

even though the client's and server's clocks were synchronized at first, they can drift out of sync again ๐Ÿ˜ฉ When that happens, the server returns an authentication status of AUTH_REJECTEDVERF to the client, and then the client should try to resynchronize โฐ

a client may also get an AUTH_BADCRED error when using a nickname that was valid before ๐Ÿฅบ That's because the server's nickname table has a limited size, and it may flush entries whenever it wants ๐Ÿ’… In this case, the client should resend its original full name credential, and the server will give it a new nickname ๐Ÿฆ‹ If a server crashes, the entire nickname table gets flushed, and every client has to resend its original credentials ๐Ÿ’€

2.4 DH Authentication Protocol Specification โœจ

Okay bestie, so there are two kinds of credentials ๐ŸŽ€. One uses the client's full network name, and the other uses its "nickname," which is just an unsigned integer the server hands out ๐ŸŒธ. The client must use its fullname in its first transaction with the server, and that's where the server sends back the nickname. After that, the client may use its nickname for all further transactions. Using the nickname isn't required, but it's wise for performance reasons โšก (it's giving efficiency queen).

Here are the definitions we use to describe the protocol ๐Ÿ’…:

   enum authdh_namekind {
      ADN_FULLNAME = 0,
      ADN_NICKNAME = 1
   };

   typedef opaque des_block[8]; /* 64-bit block of encrypted data */

   const MAXNETNAMELEN = 255;   /* maximum length of a netname */

The flavor for all DH authentication credentials and verifiers is "AUTH_DH", numerical value 3 ๐Ÿฆ‹. The opaque data for the client credential encodes this structure:

   union authdh_cred switch (authdh_namekind namekind) {
   case ADN_FULLNAME:
      authdh_fullname fullname;
   case ADN_NICKNAME:
      authdh_nickname nickname;
   };

The opaque data for a verifier that comes with a client credential encodes this one:

   union authdh_verf switch (authdh_namekind namekind) {
   case ADN_FULLNAME:
      authdh_fullname_verf fullname_verf;
   case ADN_NICKNAME:
      authdh_nickname_verf nickname_verf;
   };

And the opaque data for a verifier the server sends back in response to a client request encodes this:

   struct authdh_server_verf;

We'll go through these structures in detail below ๐Ÿงš.

2.4.1 The Full Network Name Credential and Verifier (Client)

First up, the client creates a conversation key for the session ๐Ÿ”‘. Then it fills out this structure:

   +---------------------------------------------------------------+
   |   timestamp   |  timestamp    |               |               |
   |   seconds     | micro seconds |      ttl      |   ttl - 1     |
   |   32 bits     |    32 bits    |    32 bits    |   32 bits     |
   +---------------------------------------------------------------+
   0              31              63              95             127

The fields are stored in XDR (external data representation) format. The timestamp counts the time since midnight, January 1, 1970 ๐Ÿ•›. Those 128 bits then get encrypted in DES CBC mode, using the session's conversation key and an initialization vector of 0. The result looks like this:

   +---------------------------------------------------------------+
   |               T               |               |               |
   |     T1               T2       |      W1       |     W2        |
   |   32 bits     |    32 bits    |    32 bits    |   32 bits     |
   +---------------------------------------------------------------+
   0              31              63              95             127

T1, T2, W1, and W2 are all 32-bit quantities. They still have some connection to the original values that sat in those spots, but now they depend on each other to decrypt properly ๐Ÿงฉ. The 64-bit sequence made of T1 and T2 is called T.

The full network name credential is written like this in XDR notation:

   struct authdh_fullname {
      string name<MAXNETNAMELEN>;  /* netname of client             */
      des_block key;               /* encrypted conversation key    */
      opaque w1[4];                /* W1                            */
   };

The conversation key gets encrypted with the "common key" in ECB mode. The common key is a DES key derived from the Diffie-Hellman public and private keys, which we'll cover later ๐Ÿ”.

The verifier looks like this:

   struct authdh_fullname_verf {
      des_block timestamp;         /* T (the 64 bits of T1 and T2) */
      opaque w2[4];                /* W2                           */
   };

Heads up: all the encrypted stuff (key, w1, w2, timestamp) in those structures is opaque ๐Ÿ™ˆ.

So the fullname credential and its verifier together carry the client's network name, an encrypted conversation key, the ttl, a timestamp, and a ttl verifier that's one less than the ttl ๐Ÿ’œ. The ttl is really the credential's lifetime. The server accepts the credential if the current server time is "within" the timestamp plus the ttl โฐ. If it isn't, the server rejects the credential with an authentication status of AUTH_BADCRED ๐Ÿ’€. One way to stop requests from being replayed is for the server to insist that each timestamp is greater than the previous one it saw, except on the first transaction. If a timestamp is earlier than the previous one, the server returns an authentication status of AUTH_REJECTEDCRED ๐Ÿšซ.

The server sends back an authdh_server_verf structure, which we'll dig into below. That structure holds a "nickname," which the client can use for later requests in the same conversation ๐Ÿฆ‹.

2.4.2 The Nickname Credential and Verifier (Client)

From the second transaction onward, the client can use the shorter nickname credential and verifier to be more efficient โšก. First, it fills out this structure:

   +-------------------------------+
   |   timestamp   |  timestamp    |
   |   seconds     | micro seconds |
   |   32 bits     |    32 bits    |
   +-------------------------------+
   0              31              63

The fields are stored in XDR (external data representation) format. Those 64 bits get encrypted in DES ECB mode with the session's conversation key, and the result is:

   +-------------------------------+
   |     (T1)      |      (T2)     |
   |               T               |
   |             64 bits           |
   +-------------------------------+
   0              31              63

The nickname credential in XDR notation:

   struct authdh_nickname {
      unsigned int nickname;       /* nickname returned by server   */
   };

And the nickname verifier:

   struct authdh_nickname_verf {
      des_block timestamp;         /* T (the 64 bits of T1 and T2) */
      opaque w[4];                 /* Set to zero                  */
   };

The server can reject a nickname credential for a few different reasons ๐Ÿ™…โ€โ™€๏ธ. AUTH_BADCRED means the nickname isn't valid anymore, and the client should retry the request using the fullname credential instead. AUTH_REJECTEDVERF means the nickname verifier isn't valid, and again, the client should retry with the fullname credential ๐Ÿ”.

2.4.3 The Nickname Verifier (Server)

The server never sends back a credential. It only returns one kind of verifier, the nickname verifier ๐Ÿ’Œ. Here's its XDR representation:

   struct authdh_server_verf {
      des_block timestamp_verf; /* timestamp verifier (encrypted)    */
      unsigned int nickname;    /* new client nickname (unencrypted) */
   };

The timestamp verifier is built in exactly the same way as the client's nickname credential ๐Ÿช„. The server sets the timestamp to the value the client sent, minus one second, then encrypts it in DES ECB mode using the conversation key. The server also sends the client a nickname for future transactions. That nickname isn't encrypted ๐Ÿ‘€.

2.5 Diffie-Hellman Encryption

Here we have two constants, "BASE" and "MODULUS" [3] ๐ŸŒˆ. Sun picked these specific values for the DH authentication protocol:

   const BASE = 3;
   const MODULUS = "d4a0ba0250b6fd2ec626e7efd637df76c716e22d0944b88b";

Heads up: the modulus is written above as a hexadecimal string ๐Ÿ”ข.

This scheme is easiest to understand with an example ๐Ÿซถ. Imagine two people, "A" and "B," who want to send each other encrypted messages. Both of them generate "secret" keys at random and never reveal them to anyone. Call these keys SK(A) and SK(B). They also publish their "public" keys in a public directory ๐Ÿ“–. Those are computed like this:

   PK(A) = ( BASE ** SK(A) ) mod MODULUS
   PK(B) = ( BASE ** SK(B) ) mod MODULUS

The "**" notation means exponentiation. Now A and B can both arrive at the "common" key between them, written here as CK(A, B), without ever revealing their secret keys ๐Ÿคซ.

A computes:

   CK(A, B) = ( PK(B) ** SK(A)) mod MODULUS

while B computes:

   CK(A, B) = ( PK(A) ** SK(B)) mod MODULUS

These two can be shown to be equivalent:

   (PK(B) ** SK(A)) mod MODULUS = (PK(A) ** SK(B)) mod MODULUS

To keep things simple, we drop the "mod MODULUS" parts and assume modulo arithmetic:

   PK(B) ** SK(A) = PK(A) ** SK(B)

Then we replace PK(B) with what B computed earlier, and PK(A) the same way:

   (BASE ** SK(B)) ** SK(A) = (BASE ** SK(A)) ** SK(B)

Which leads to:

   BASE ** (SK(A) * SK(B)) = BASE ** (SK(A) * SK(B))

Okay, here's the spicy part ๐ŸŒถ๏ธ. The common key CK(A, B) isn't used to encrypt the timestamps. It's only used to encrypt a conversation key, and that conversation key is what encrypts the timestamps ๐Ÿ”. Why the extra step? The idea is to use the common key as little as possible, since it might get broken someday. Breaking a conversation key is way less damaging, because conversations are pretty short-lived โณ.

The conversation key is encrypted with 56-bit DES keys, but the common key is 192 bits long. To cut the bits down, 56 bits get picked out of the common key like this: the middle-most 8 bytes are selected, and then parity is added to the lowest-order bit of each byte. That gives a 56-bit key with 8 bits of parity ๐Ÿงฎ.

Only 48 bits of the 8-byte conversation key are actually used in the DH Authentication scheme. The least and most significant bits of each byte of the conversation key go unused ๐Ÿ™ƒ.

3. Kerberos-based Authentication โœจ

Conceptually, Kerberos-based authentication is a lot like DH authentication ๐Ÿ‘ฏ. The big difference is that Kerberos-based authentication takes advantage of the fact that Kerberos tickets have the client name and the conversation key encoded in them ๐ŸŽซ. This RFC doesn't describe Kerberos name syntax, protocols, or ticket formats, so for those you'll want to check out [6], [7], and [8] ๐Ÿ“š.

3.1 Naming

A Kerberos name has three parts ๐Ÿท๏ธ. The first is the principal name, which is usually a user's or a service's name. The second is the instance, which for a user is usually NULL. Some users may have privileged instances, though, like root or admin ๐Ÿ‘‘. For a service, the instance is the name of the machine it runs on. So an NFS service running on the machine ABC is different from an NFS service running on the machine XYZ ๐Ÿ–ฅ๏ธ. The third part is the realm. The realm corresponds to the Kerberos service that provides authentication for the principal ๐ŸŒ. When you write a Kerberos name, the principal name is separated from the instance (if it isn't NULL) by a period. The realm (if it isn't the local realm) follows, preceded by an "@" sign. Here are some examples of valid Kerberos names ๐Ÿ’–:

   billb
   jis.admin
   srz@lcs.mit.edu
   treese.root@athena.mit.edu

3.2 Kerberos-based Authentication Protocol Specification โœจ

okay so this is where the Kerberos stuff gets real ๐Ÿ” and it's based on Kerberos version 4, so it's a little vintage, but still iconic. there are two kinds of credentials: one where the client uses its full network name, and one where it uses its "nickname," which is literally just an unsigned integer the server hands out ๐Ÿ“. the client must use its fullname in its first transaction, because that's when the server gives back the nickname. after that the client may use the nickname for all further transactions. there's no requirement to use it, but it is wise to, for performance reasons ๐Ÿš€

here are the definitions we're working with:

enum authkerb4_namekind {
   AKN_FULLNAME = 0,
   AKN_NICKNAME = 1
};

the flavor for every Kerberos-based authentication credential and verifier is "AUTH_KERB4", with numerical value 4 ๐Ÿ’–. the opaque data in the client credential encodes this structure:

union authkerb4_cred switch (authkerb4_namekind namekind) {
case AKN_FULLNAME:
   authkerb4_fullname fullname;
case AKN_NICKNAME:
   authkerb4_nickname nickname;
};

the opaque data in a verifier that goes along with a client credential encodes this one:

union authkerb4_verf switch (authkerb4_namekind namekind) {
case AKN_FULLNAME:
   authkerb4_fullname_verf fullname_verf;
case AKN_NICKNAME:
   authkerb4_nickname_verf nickname_verf;
};

and the opaque data in a verifier the server sends back in response to a client request encodes this:

struct authkerb4_server_verf;

we'll go through all of these structures in detail below ๐Ÿงš

3.2.1 The Full Network Name Credential and Verifier (Client)

bestie, first the client has to get a Kerberos ticket from the Kerberos Server ๐ŸŽŸ๏ธ. that ticket holds a Kerberos session key, which becomes the conversation key ๐Ÿ—๏ธ. next, the client fills out this structure:

   +---------------------------------------------------------------+
   |   timestamp   |  timestamp    |               |               |
   |   seconds     | micro seconds |      ttl      |   ttl - 1     |
   |   32 bits     |    32 bits    |    32 bits    |   32 bits     |
   +---------------------------------------------------------------+
   0              31              63              95             127

the fields are stored in XDR (external data representation) format. the timestamp counts the time since midnight, January 1, 1970 โฐ. "ttl" means the same thing as the matching field in Diffie-Hellman authentication: it's the credential "time-to-live" for the conversation being started โœจ. those 128 bits then get encrypted with DES in CBC mode, using the conversation key and an initialization vector of 0. the result looks like this:

   +---------------------------------------------------------------+
   |               T               |               |               |
   |     T1               T2       |      W1       |     W2        |
   |   32 bits     |    32 bits    |    32 bits    |   32 bits     |
   +---------------------------------------------------------------+
   0              31              63              95             127

T1, T2, W1, and W2 are all 32-bit quantities. they still correspond to the original values in their positions, but now they depend on each other to decrypt properly ๐ŸŒ€. the 64-bit sequence made of T1 and T2 is called T.

here's the full network name credential in XDR notation:

struct authkerb4_fullname {
   opaque ticket<>;         /* kerberos ticket for the server */
   opaque w1[4];            /* W1                             */
};

and the verifier:

struct authkerb4_fullname_verf {
   des_block timestamp;         /* T (the 64 bits of T1 and T2) */
   opaque w2[4];                /* W2                           */
};

note that all the client-encrypted stuff (w1, w2, timestamp) in those structures is opaque ๐Ÿซถ. the client does not encrypt the Kerberos ticket for the server.

together, the fullname credential and its verifier carry the Kerberos ticket (which has the client name and the conversation key), the ttl, a timestamp, and a ttl verifier that's one less than the ttl. the ttl is really the lifetime of the credential. the server accepts the credential if the current server time is "within" the timestamp plus the ttl โœ…. otherwise the server rejects it with an authentication status of AUTH_BADCRED ๐Ÿ’€. one way to stop requests from being replayed is for the server to insist that each timestamp is greater than the previous one it saw, except on the first transaction. if a timestamp is earlier than the previous one seen, the server returns an authentication status of AUTH_REJECTEDCRED ๐Ÿ™…โ€โ™€๏ธ

the server sends back an authkerb4_server_verf structure, which is described in detail below. this structure includes a "nickname," which can be used for later requests in the current session ๐ŸŒธ

3.2.2 The Nickname Credential and Verifier (Client)

in transactions after the first one, the client can use the shorter nickname credential and verifier to be efficient โšก. first, the client fills out this structure:

   +-------------------------------+
   |   timestamp   |  timestamp    |
   |   seconds     | micro seconds |
   |   32 bits     |    32 bits    |
   +-------------------------------+
   0              31              63

the fields are stored in XDR format. those 64 bits get encrypted with DES in ECB mode, using the conversation key for the session. the result:

   +-------------------------------+
   |     (T1)      |      (T2)     |
   |               T               |
   |             64 bits           |
   +-------------------------------+
   0              31              63

the nickname credential, in XDR notation:

struct authkerb4_nickname {
   unsigned int nickname;       /* nickname returned by server   */
};

and the nickname verifier:

struct authkerb4_nickname_verf {
   des_block timestamp;         /* T (the 64 bits of T1 and T2) */
   opaque w[4];                 /* Set to zero                  */
};

the server can reject the nickname credential for a few reasons ๐Ÿ™ˆ. AUTH_BADCRED means the nickname is no longer valid, so the client should retry with the fullname credential. AUTH_REJECTEDVERF means the nickname verifier isn't valid, and again the client should retry with the fullname credential. AUTH_TIMEEXPIRE means the session's Kerberos ticket has expired, so the client should start a new session by getting a new Kerberos ticket ๐ŸŽ€

3.2.3 The Nickname Verifier (Server)

the server never returns a credential. it only ever returns one kind of verifier, the nickname verifier ๐Ÿง. it has this XDR representation:

struct authkerb4_server_verf {
   des_block timestamp_verf; /* timestamp verifier (encrypted)    */
   unsigned int nickname;    /* new client nickname (unencrypted) */
};

the timestamp verifier gets built in exactly the same way as the client's nickname credential. the server sets the timestamp value to what the client sent, minus one second, then encrypts it with DES in ECB mode using the conversation key ๐Ÿ”‘. the server also sends the client a nickname to use in future transactions, and that nickname is unencrypted.

3.2.4 Kerberos-specific Authentication Status Values

the server may send back one of these errors in the authentication status field:

enum auth_stat {
    ...
    /*
     * kerberos errors
     */
    AUTH_KERB_GENERIC = 8,  /* Any Kerberos-specific error other
                               than the following                   */
    AUTH_TIMEEXPIRE = 9,    /* The client's ticket has expired      */
    AUTH_TKT_FILE = 10,     /* The server was unable to find the
                               ticket file.  The client should
                               create a new session by obtaining a
                               new ticket                           */
    AUTH_DECODE = 11,       /* The server is unable to decode the
                               authenticator of the client's ticket */
    AUTH_NET_ADDR = 12      /* The network address of the client
                               does not match the address contained
                               in the ticket                        */

    /* and more to be defined */
};

4. Security Considerations ๐Ÿ”

the DH authentication mechanism and the Kerberos V4 authentication mechanism are described in this document only for informational purposes ๐Ÿ“š.

on top of the weakness pointed out earlier in this document (see WARNING on page 1), these two security mechanisms don't support integrity or privacy data protection ๐Ÿ˜ญ. it is strongly recommended that new applications use more secure mechanisms, and that existing applications migrate to more robust mechanisms ๐Ÿ›ก๏ธ.

the RPCSEC_GSS ONC RPC security flavor, specified in RFC 2203, lets applications built on top of RPC use security mechanisms that follow the GSS-API specification ๐Ÿ’ซ. it gives you a GSS-API based security framework that supports strong security mechanisms. RFC 1964 describes the Kerberos Version 5 GSS-API security mechanism, which provides integrity and privacy in addition to authentication ๐Ÿ‘‘. RFC 2623 [14] describes how Kerberos V5 is plugged into RPCSEC_GSS, and how Versions 2 and 3 of the NFS protocol use Kerberos V5 through RPCSEC_GSS. the RPCSEC_GSS/GSS-API/Kerberos-V5 stack is a robust security mechanism for applications that need strong protection, so that's the glow-up to aim for ๐Ÿฆ‹โœจ

5. References ๐Ÿ“š

Bestie, here are the receipts ๐Ÿงพ every source this spec leans on, listed exactly as cited:

  • [1] Srinivasan, R., "Remote Procedure Call Protocol Version 2", RFC 1831, August 1995.
  • [2] Srinivasan, R., "XDR: External Data Representation Standard", RFC 1832, August 1995.
  • [3] Diffie & Hellman, "New Directions in Cryptography", IEEE Transactions on Information Theory IT-22, November 1976.
  • [4] Mills, D., "Network Time Protocol (Version 3)", RFC 1305, March 1992.
  • [5] National Bureau of Standards, "Data Encryption Standard", Federal Information Processing Standards Publication 46, January 1977.
  • [6] Miller, S., Neuman, C., Schiller, J. and J. Saltzer, "Section E.2.1: Kerberos Authentication and Authorization System", December 1987.
  • [7] Steiner, J., Neuman, C. and J. Schiller, "Kerberos: An Authentication Service for Open Network Systems", pp. 191-202 in Usenix Conference Proceedings, Dallas, Texas, February, 1988.
  • [8] Kohl, J. and C. Neuman, "The Kerberos Network Authentication Service (V5)", RFC 1510, September 1993.
  • [9] La Macchia, B.A., and Odlyzko, A.M., "Computation of Discrete Logarithms in Prime Fields", pp. 47-62 in "Designs, Codes and Cryptography", Kluwer Academic Publishers, 1991.
  • [10] Cheswick, W.R., and Bellovin, S.M., "Firewalls and Internet Security," Addison-Wesley, 1995.
  • [11] Linn, J., "The Kerberos Version 5 GSS-API Mechanism", RFC 1964, June 1996.
  • [12] Linn, J., "Generic Security Service Application Program Interface, Version 2", RFC 2078, January 1997.
  • [13] Eisler, M., Chiu, A., and Ling, L., "RPCSEC_GSS Protocol Specification", RFC 2203, September 1997.
  • [14] Eisler, M., "NFS Version 2 and Version 3 Security Issues and the NFS Protocol's Use of RPCSEC_GSS and Kerberos V5", RFC 2623, June 1999.

6. Author's Address ๐ŸŽ€

Here's where to find the author, Alex Chiu, at Sun Microsystems ๐Ÿ’œ

Alex Chiu
Sun Microsystems, Inc.
901 San Antonio Road
Palo Alto, CA 94303

Phone: +1 (650) 786-6465
EMail: alex.chiu@Eng.sun.com

Copyright (C) The Internet Society (1999). All Rights Reserved.

Okay, the legal bit, but make it cute ๐Ÿฆ‹ Anyone can copy and share this document and translations of it, and can make derivative works that comment on or explain it or help implement it, and publish and distribute those in whole or in part with no restriction of any kind. The one condition is that the above copyright notice and this paragraph stay on all those copies and derivative works.

Now the important catch ๐Ÿ‘€ this document itself may not be modified in any way, such as by removing the copyright notice or the references to the Internet Society or other Internet organizations. The exceptions are when it's needed for developing Internet standards, in which case the procedures for copyrights defined in the Internet Standards process must be followed, or when it's translated into languages other than English.

The limited permissions above are perpetual and will not be revoked by the Internet Society or its successors or assigns ๐Ÿ’–

This document and the information in it is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS 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.

Acknowledgement ๐ŸŒˆ

Funding for the RFC Editor function is currently provided by the Internet Society ๐Ÿซถ

๐Ÿ“ฆ where this page comes from