Subject: Re: SSH GSSAPI key exchange

From: Simon Wilkinson <[email-masked]>
Date: Wed, 21 Feb 2001 17:41:12 +0000

On Mon, 19 Feb 2001, Jeffrey Hutzelman wrote:
> BTW, I'm interested in knowing a bit more about your implementation...

Its based on OpenSSH, and has been tested with the Kerberos GSSAPI mechanism, 
although the implementation itself should be generic enough to allow any 
other mechanism to be added (although an equivalent to 'kuserok' would be 
required in order to make external-keyx work). I have implemented the 
external-keyx user authentication, but not the 'none' method described for 
host keys.

> - Did you implement the GSSAPI user auth methods described in
>   <draft-galb-secsh-gssapi-00.txt> ?

Not yet, I hadn't encountered this draft until you mentioned it - I'm looking 
at it now.

A further issue with your draft is in the protocol section - the GSSAPI 
support in MIT Kerberos does the following (which is legal according to the 
GSSAPI RFC):

C: init_sec_context returns CONTINUE_NEEDED with data
C->S: sends data (SSH_MSG_GSSAPI_INIT)
S: accept_sec_context returns COMPLETE with data

According to the draft, the server jumps to step 4, meaning that the client 
never gets its final data packet, and never completes its context 
initialisation (the server also never receives e if the SHOULD in step 2 is 
followed, and so the process fails)

To complete the authentication sucessfully, the following steps are required:
S->C sends data (SSH_MSG_GSSAPI_CONTINUE)
C: init_sec_context returns COMPLETE with no data
C->S sends e with no data (SSH_MSG_GSSAPI_INIT, with boolean true)

The converse case, where the client returns COMPLETE, with a data packet for 
the server, is handled correctly by step 2.

I've got around this problem in my implementation by amending the protocol
as follows:

Replace the first line of step 3 with:
	If the token received from C has non-zero length, then S calls
	gss_accept_sec_context with the token. If C is zero, and the
	previous call to gss_accept_sec_context did not return
	GSS_S_COMPLETE then an error has occured.
	Otherwise processing continues with step 4

Add the following to the end of step 3:	
*	If the resulting major status code is GSS_S_COMPLETE and the
	output token has a non-zero length, then the output token is sent
	to C, and processing continues with step 2

A further concern is of the failure of the GSSAPI key exchange, especially
during rekeying. I can't find any mention of what happens following a failed 
key exchange. However, if connections must be terminated, as opposed to 
trying again using a different algorithm, then this could cause severe 
problems for Kerberos users whose local credentials expire during a long 
running ssh operation.

It would be possible to prevent this partially in implementation, by only 
offering a gss- algorithm if init-sec-context is known to succeed, but this
is rather inelegant.

Cheers,

Simon.

---

From: Joseph Salowey <[email-masked]>
Date: Wed, 21 Feb 2001 10:27:43 -0800

Good catch,

Prhaps we should modify things as follows

1. C s

---

From: Joseph Salowey <[email-masked]>
Date: Wed, 21 Feb 2001 10:44:37 -0800

Good catch,

Perhaps we should always send e with the inital token even if the context 
is not yet complete.  I don't think there is a problem sending e if the 
context does not complete, it might be extra processing for the client, but 
I' not sure this is a problem.

1  C sends initial context token and e to S even if CONTINUE_NEEDED is returned
2  S calls Accept sec context and stores e
     if COMPLETE
         check context for mutual_auth and integrity ready
         if non zero token send token to C
         send MIC of H to C
     if continue needed
          send token to C
3  C calls init_sec_context with token (if present)
     if COMPLETE
         C checks context for mutual_auth and integrity ready
         verify MIC of H

Since e does not have to be integrity protected directly it can be sent 
with the initial token.  This might eliminate an extra round trip.

Joe

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Wed, 21 Feb 2001 15:01:38 -0500 (EST)

> external-keyx user authentication, but not the 'none' method described for 

Hm.  So, a machine still must have an ssh host key, even though it will
not be used as part of the GSSAPI key exchange.

> problems for Kerberos users whose local credentials expire during a long 

I'll have to re-read the core ssh drafts, but I believe the only action
that can be taken after a failed key exchange is to drop the connection.
However, I fail to see how this has an effect on expired user credentials.
The key exchange happens only at the start of a connection; if the user's
credentials are expired, he must get new ones before establishing a
connection.  Of course, it is also worth noting that some GSSAPI mechs
(particularly public-key based ones) have credentials with much longer
expiration times than those typically used in Kerberos.

-- Jeffrey T. Hutzelman (N3NHS) <[email-masked]>
   Sr. Research Systems Programmer
   School of Computer Science - Research Computing Facility
   Carnegie Mellon University - Pittsburgh, PA

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Wed, 21 Feb 2001 14:56:45 -0500 (EST)

> I' not sure this is a problem.

I don't think there's any problem with sending e before the context is
established.  In fact, I was initially going to write the spec that way,
but doing it last seemed to make both the protocol and the text cleaner. 
Sending it first does seem to save a half round trip, but the way I read
the GSSAPI spec, _every_ call to gss_init_sec_context results in a token
that must be sent to the server.  It would seem now that this is not true;
it's possible for the acceptor to send the last message.

Let's assume, then, that either initiator or acceptor can be the last to
send, and will return COMPLETE iff it is not expecting a reply.  Then I
think we should do the following:

- Change the wording of step 2 such that the client MUST send e with
  the first message sent to the server (formerly, we said the client
  SHOULD send it with the last message, but MAY send it in some other
  message instead.  Now, the client doesn't know if it is sending the
  last message).

- Change the wording of step 2 such that is is an error if the call
  to gss_init_sec_context does not produce a token.  If there is a
  final token, we'll handle it later.

- Change the wording of step 3 such that a final token may be sent to
  the client.

- Insert step 4a, in which the client calls gss_init_sec_context to
  process the server's final token, if there is one.  This call is
  like the one in step 2, except that it is an error for the call to
  return a token or any status other than GSS_S_COMPLETE.  This step
  is performed only if no previous call to gss_init_sec_context had
  a status of GSS_S_COMPLETE.

- Adjust the message flow description to match the changes, including
  a change in the definition of SSH_MSG_GSSAPI_COMPLETE to include an
  optional final token.

- We should make it clear that it is an error for the server to send
  SSH_MSG_GSSAPI_COMPLETE without a final token if the client is still
  expecting one.  For safety, it should also be an error for the server
  to send SSH_MSG_GSSAPI_CONTINUE or SSH_MSG_GSSAPI_COMPLETE with a
  final token if the client has already seen a GSS_S_COMPLETE status.

So, we have the client and server trading messages as follows:

- client calls gss_init_sec_context, with the server's last token if
  any.  This must result in a token, which is sent to the server in a
  message of type SSH_MSG_GSSAPI_INIT.

- server calls gss_accept_sec_context.  If the result status is
  GSS_S_CONTINUE_NEEDED, there must be a token, which is sent to the
  client in an SSH_MSG_GSSAPI_CONTINUE message.  If the result status
  is GSS_S_COMPLETE, then an SSH_MSG_GSSAPI_COMPLETE message is sent,
  containing 'f', a MIC of the exchange hash, and a final token if
  there is one.

- On receiving SSH_MSG_GSSAPI_CONTINUE, the client goes to the top,
  calling gss_init_sec_context again.  It is an error for this to
  happen if the previous call to gss_init_sec_context resulted in a
  GSS_S_COMPLETE status.

- On receiving SSH_MSG_GSSAPI_COMPLETE, the client makes one last
  call to gss_init_sec_context iff the server provides a final token.
  It is an error for a final token to be present if the previous
  call resulted in a GSS_S_COMPLETE status, or for a final token to
  be absent if the previous call resulted in GSS_S_CONTINUE_NEEDED.

I think this addresses the problem of the server sending the last
message, as well as preventing the extra round trip that Joe was
concerned about.

-- Jeff

---

From: Simon Wilkinson <[email-masked]>
Date: Wed, 21 Feb 2001 20:42:55 +0000

On Wed, 21 Feb 2001, Jeffrey Hutzelman wrote:
> The key exchange happens only at the start of a connection; 

My concern was when a server requests that new keys be established for the 
connection, which according to the core drafts should take place hourly. If 
the users credentials have expired between connection establishment, and 
rekeying, then I think, from my reading of the drafts, that their existing 
connection would be dropped.

Cheers,

Simon.