This section defines a class of key exchange methods that combine the
Diffie-Hellman key exchange from Section 8 of [SSH-TRANSPORT] with
mutual authentication using GSS-API.
Since the GSS-API key exchange methods described in this section do
not require the use of public key signature or encryption algorithms,
they MAY be used with any host key algorithm, including the "null"
algorithm described in Section 5.
The following symbols are used in this description:
o C is the client, and S is the server
o p is a large safe prime, g is a generator for a subgroup of GF(p),
and q is the order of the subgroup
o V_S is S's version string, and V_C is C's version string
o I_C is C's KEXINIT message, and I_S is S's KEXINIT message
1. C generates a random number x (1 < x < q) and computes e = g^x
mod p.
2. C calls GSS_Init_sec_context(), using the most recent reply token
received from S during this exchange, if any. For this call, the
client MUST set mutual_req_flag to "true" to request that mutual
authentication be performed. It also MUST set integ_req_flag to
"true" to request that per-message integrity protection be
supported for this context. In addition, deleg_req_flag MAY be
set to "true" to request access delegation, if requested by the
user. Since the key exchange process authenticates only the
host, the setting of anon_req_flag is immaterial to this process.
If the client does not support the "gssapi-keyex" user
authentication method described in Section 4, or does not intend
to use that method in conjunction with the GSS-API context
established during key exchange, then anon_req_flag SHOULD be set
to "true". Otherwise, this flag MAY be set to true if the client
wishes to hide its identity. Since the key exchange process will
involve the exchange of only a single token once the context has
been established, it is not necessary that the GSS-API context
support detection of replayed or out-of-sequence tokens. Thus,
replay_det_req_flag and sequence_req_flag need not be set for
this process. These flags SHOULD be set to "false".
* If the resulting major_status code is GSS_S_COMPLETE and the
mutual_state flag is not true, then mutual authentication has
not been established, and the key exchange MUST fail.
* If the resulting major_status code is GSS_S_COMPLETE and the
integ_avail flag is not true, then per-message integrity
protection is not available, and the key exchange MUST fail.
* If the resulting major_status code is GSS_S_COMPLETE and both
the mutual_state and integ_avail flags are true, the resulting
output token is sent to S.
* If the resulting major_status code is GSS_S_CONTINUE_NEEDED,
the output_token is sent to S, which will reply with a new
token to be provided to GSS_Init_sec_context().
* The client MUST also include "e" with the first message it
sends to the server during this process; if the server
receives more than one "e" or none at all, the key exchange
fails.
* It is an error if the call does not produce a token of non-
zero length to be sent to the server. In this case, the key
exchange MUST fail.
3. S calls GSS_Accept_sec_context(), using the token received from
C.
* If the resulting major_status code is GSS_S_COMPLETE and the
mutual_state flag is not true, then mutual authentication has
not been established, and the key exchange MUST fail.
* If the resulting major_status code is GSS_S_COMPLETE and the
integ_avail flag is not true, then per-message integrity
protection is not available, and the key exchange MUST fail.
* If the resulting major_status code is GSS_S_COMPLETE and both
the mutual_state and integ_avail flags are true, then the
security context has been established, and processing
continues with step 4.
* If the resulting major_status code is GSS_S_CONTINUE_NEEDED,
then the output token is sent to C, and processing continues
with step 2.
* If the resulting major_status code is GSS_S_COMPLETE, but a
non-zero-length reply token is returned, then that token is
sent to the client.
4. S generates a random number y (0 < y < q) and computes f = g^y
mod p. It computes K = e ^ y mod p, and H = hash(V_C || V_S ||
I_C || I_S || K_S || e || f || K). It then calls GSS_GetMIC() to
obtain a GSS-API message integrity code for H. S then sends f
and the message integrity code (MIC) to C.
5. This step is performed only (1) if the server's final call to
GSS_Accept_sec_context() produced a non-zero-length final reply
token to be sent to the client and (2) if no previous call by the
client to GSS_Init_sec_context() has resulted in a major_status
of GSS_S_COMPLETE. Under these conditions, the client makes an
additional call to GSS_Init_sec_context() to process the final
reply token. This call is made exactly as described above.
However, if the resulting major_status is anything other than
GSS_S_COMPLETE, or a non-zero-length token is returned, it is an
error and the key exchange MUST fail.
6. C computes K = f^x mod p, and H = hash(V_C || V_S || I_C || I_S
|| K_S || e || f || K). It then calls GSS_VerifyMIC() to verify
that the MIC sent by S matches H. If the MIC is not successfully
verified, the key exchange MUST fail.
Either side MUST NOT send or accept e or f values that are not in the
range [1,p-1]. If this condition is violated, the key exchange
fails.
If any call to GSS_Init_sec_context() or GSS_Accept_sec_context()
returns a major_status other than GSS_S_COMPLETE or
GSS_S_CONTINUE_NEEDED, or any other GSS-API call returns a
major_status other than GSS_S_COMPLETE, the key exchange fails. In
this case, several mechanisms are available for communicating error
information to the peer before terminating the connection as required
by [SSH-TRANSPORT]:
o If the key exchange fails due to any GSS-API error on the server
(including errors returned by GSS_Accept_sec_context()), the
server MAY send a message informing the client of the details of
the error. In this case, if an error token is also sent (see
below), then this message MUST be sent before the error token.
o If the key exchange fails due to a GSS-API error returned from the
server's call to GSS_Accept_sec_context(), and an "error token" is
also returned, then the server SHOULD send the error token to the
client to allow completion of the GSS security exchange.
o If the key exchange fails due to a GSS-API error returned from the
client's call to GSS_Init_sec_context(), and an "error token" is
also returned, then the client SHOULD send the error token to the
server to allow completion of the GSS security exchange.
As noted in Section 9, it may be desirable under site security policy
to obscure information about the precise nature of the error; thus,
it is RECOMMENDED that implementations provide a method to suppress
these messages as a matter of policy.
This is implemented with the following messages. The hash algorithm
for computing the exchange hash is defined by the method name, and is
called HASH. The group used for Diffie-Hellman key exchange and the
underlying GSS-API mechanism are also defined by the method name.
After the client's first call to GSS_Init_sec_context(), it sends the
following:
byte SSH_MSG_KEXGSS_INIT
string output_token (from GSS_Init_sec_context())
mpint e
Upon receiving the SSH_MSG_KEXGSS_INIT message, the server MAY send
the following message, prior to any other messages, to inform the
client of its host key.
byte SSH_MSG_KEXGSS_HOSTKEY
string server public host key and certificates (K_S)
Since this key exchange method does not require the host key to be
used for any encryption operations, this message is OPTIONAL. If the
"null" host key algorithm described in Section 5 is used, this
message MUST NOT be sent. If this message is sent, the server public
host key(s) and/or certificate(s) in this message are encoded as a
single string, in the format specified by the public key type in use
(see [SSH-TRANSPORT], Section 6.6).
In traditional SSH deployments, host keys are normally expected to
change infrequently, and there is often no mechanism for validating
host keys not already known to the client. As a result, the use of a
new host key by an already-known host is usually considered an
indication of a possible man-in-the-middle attack, and clients often
present strong warnings and/or abort the connection in such cases.
By contrast, when GSS-API-based key exchange is used, host keys sent
via the SSH_MSG_KEXGSS_HOSTKEY message are authenticated as part of
the GSS-API key exchange, even when previously unknown to the client.
Further, in environments in which GSS-API-based key exchange is used
heavily, it is possible and even likely that host keys will change
much more frequently and/or without advance warning.
Therefore, when a new key for an already-known host is received via
the SSH_MSG_KEXGSS_HOSTKEY message, clients SHOULD NOT issue strong
warnings or abort the connection, provided the GSS-API-based key
exchange succeeds.
In order to facilitate key re-exchange after the user's GSS-API
credentials have expired, client implementations SHOULD store host
keys received via SSH_MSG_KEXGSS_HOSTKEY for the duration of the
session, even when such keys are not stored for long-term use.
Each time the server's call to GSS_Accept_sec_context() returns a
major_status code of GSS_S_CONTINUE_NEEDED, it sends the following
reply to the client:
byte SSH_MSG_KEXGSS_CONTINUE
string output_token (from GSS_Accept_sec_context())
If the client receives this message after a call to
GSS_Init_sec_context() has returned a major_status code of
GSS_S_COMPLETE, a protocol error has occurred and the key exchange
MUST fail.
Each time the client receives the message described above, it makes
another call to GSS_Init_sec_context(). It then sends the following:
byte SSH_MSG_KEXGSS_CONTINUE
string output_token (from GSS_Init_sec_context())
The server and client continue to trade these two messages as long as
the server's calls to GSS_Accept_sec_context() result in major_status
codes of GSS_S_CONTINUE_NEEDED. When a call results in a
major_status code of GSS_S_COMPLETE, it sends one of two final
messages.
If the server's final call to GSS_Accept_sec_context() (resulting in
a major_status code of GSS_S_COMPLETE) returns a non-zero-length
token to be sent to the client, it sends the following:
byte SSH_MSG_KEXGSS_COMPLETE
mpint f
string per_msg_token (MIC of H)
boolean TRUE
string output_token (from GSS_Accept_sec_context())
If the client receives this message after a call to
GSS_Init_sec_context() has returned a major_status code of
GSS_S_COMPLETE, a protocol error has occurred and the key exchange
MUST fail.
If the server's final call to GSS_Accept_sec_context() (resulting in
a major_status code of GSS_S_COMPLETE) returns a zero-length token or
no token at all, it sends the following:
byte SSH_MSG_KEXGSS_COMPLETE
mpint f
string per_msg_token (MIC of H)
boolean FALSE
If the client receives this message when no call to
GSS_Init_sec_context() has yet resulted in a major_status code of
GSS_S_COMPLETE, a protocol error has occurred and the key exchange
MUST fail.
If either the client's call to GSS_Init_sec_context() or the server's
call to GSS_Accept_sec_context() returns an error status and produces
an output token (called an "error token"), then the following SHOULD
be sent to convey the error information to the peer:
byte SSH_MSG_KEXGSS_CONTINUE
string error_token
If a server sends both this message and an SSH_MSG_KEXGSS_ERROR
message, the SSH_MSG_KEXGSS_ERROR message MUST be sent first, to
allow clients to record and/or display the error information before
processing the error token. This is important because a client
processing an error token will likely disconnect without reading any
further messages.
In the event of a GSS-API error on the server, the server MAY send
the following message before terminating the connection:
byte SSH_MSG_KEXGSS_ERROR
uint32 major_status
uint32 minor_status
string message
string language tag
The message text MUST be encoded in the UTF-8 encoding described in
[UTF8]. Language tags are those described in [LANGTAG]. Note that
the message text may contain multiple lines separated by carriage
return-line feed (CRLF) sequences. Application developers should
take this into account when displaying these messages.
The hash H is computed as the HASH hash of the concatenation of the
following:
string V_C, the client's version string (CR, NL excluded)
string V_S, the server's version string (CR, NL excluded)
string I_C, the payload of the client's SSH_MSG_KEXINIT
string I_S, the payload of the server's SSH_MSG_KEXINIT
string K_S, the host key
mpint e, exchange value sent by the client
mpint f, exchange value sent by the server
mpint K, the shared secret
This value is called the exchange hash, and it is used to
authenticate the key exchange. The exchange hash SHOULD be kept
secret. If no SSH_MSG_KEXGSS_HOSTKEY message has been sent by the
server or received by the client, then the empty string is used in
place of K_S when computing the exchange hash.
The GSS_GetMIC call MUST be applied over H, not the original data.
2.2. Group Exchange
This section describes a modification to the generic GSS-API-
authenticated Diffie-Hellman key exchange to allow the negotiation of
the group to be used, using a method based on that described in
[GROUP-EXCHANGE].
The server keeps a list of safe primes and corresponding generators
that it can select from. These are chosen as described in Section 3
of [GROUP-EXCHANGE]. The client requests a modulus from the server,
indicating the minimum, maximum, and preferred sizes; the server
responds with a suitable modulus and generator. The exchange then
proceeds as described in Section 2.1 above.
This description uses the following symbols, in addition to those
defined above:
o n is the size of the modulus p in bits that the client would like
to receive from the server
o min and max are the minimal and maximal sizes of p in bits that
are acceptable to the client
1. C sends "min || n || max" to S, indicating the minimal acceptable
group size, the preferred size of the group, and the maximal
group size in bits the client will accept.
2. S finds a group that best matches the client's request, and sends
"p || g" to C.
3. The exchange proceeds as described in Section 2.1 above,
beginning with step 1, except that the exchange hash is computed
as described below.
Servers and clients SHOULD support groups with a modulus length of k
bits, where 1024 <= k <= 8192. The recommended values for min and
max are 1024 and 8192, respectively.
This is implemented using the following messages, in addition to
those described above:
First, the client sends:
byte SSH_MSG_KEXGSS_GROUPREQ
uint32 min, minimal size in bits of an acceptable group
uint32 n, preferred size in bits of the group the server
should send
uint32 max, maximal size in bits of an acceptable group
The server responds with:
byte SSH_MSG_KEXGSS_GROUP
mpint p, safe prime
mpint g, generator for subgroup in GF(p)
This is followed by the message exchange described above in
Section 2.1, except that the exchange hash H is computed as the HASH
hash of the concatenation of the following:
string V_C, the client's version string (CR, NL excluded)
string V_S, the server's version string (CR, NL excluded)
string I_C, the payload of the client's SSH_MSG_KEXINIT
string I_S, the payload of the server's SSH_MSG_KEXINIT
string K_S, the host key
uint32 min, minimal size in bits of an acceptable group
uint32 n, preferred size in bits of the group the server
should send
uint32 max, maximal size in bits of an acceptable group
mpint p, safe prime
mpint g, generator for subgroup in GF(p)
mpint e, exchange value sent by the client
mpint f, exchange value sent by the server
mpint K, the shared secret
2.3. gss-group1-sha1-*
Each of these methods specifies GSS-API-authenticated Diffie-Hellman
key exchange as described in Section 2.1 with SHA-1 as HASH, and the
group defined in Section 8.1 of [SSH-TRANSPORT]. The method name for
each method is the concatenation of the string "gss-group1-sha1-"
with the Base64 encoding of the MD5 hash [MD5] of the ASN.1
Distinguished Encoding Rules (DER) encoding [ASN1] of the underlying
GSS-API mechanism's Object Identifier (OID). Base64 encoding is
described in Section 6.8 of [MIME].
Each and every such key exchange method is implicitly registered by
this specification. The IESG is considered to be the owner of all
such key exchange methods; this does NOT imply that the IESG is
considered to be the owner of the underlying GSS-API mechanism.
2.4. gss-group14-sha1-*
Each of these methods specifies GSS-API authenticated Diffie-Hellman
key exchange as described in Section 2.1 with SHA-1 as HASH, and the
group defined in Section 8.2 of [SSH-TRANSPORT]. The method name for
each method is the concatenation of the string "gss-group14-sha1-"
with the Base64 encoding of the MD5 hash [MD5] of the ASN.1 DER
encoding [ASN1] of the underlying GSS-API mechanism's OID. Base64
encoding is described in Section 6.8 of [MIME].
Each and every such key exchange method is implicitly registered by
this specification. The IESG is considered to be the owner of all
such key exchange methods; this does NOT imply that the IESG is
considered to be the owner of the underlying GSS-API mechanism.
2.5. gss-gex-sha1-*
Each of these methods specifies GSS-API-authenticated Diffie-Hellman
key exchange as described in Section 2.2 with SHA-1 as HASH. The
method name for each method is the concatenation of the string "gss-
gex-sha1-" with the Base64 encoding of the MD5 hash [MD5] of the
ASN.1 DER encoding [ASN1] of the underlying GSS-API mechanism's OID.
Base64 encoding is described in Section 6.8 of [MIME].
Each and every such key exchange method is implicitly registered by
this specification. The IESG is considered to be the owner of all
such key exchange methods; this does NOT imply that the IESG is
considered to be the owner of the underlying GSS-API mechanism.
Key exchange method names starting with "gss-" are reserved for key
exchange methods that conform to this document; in particular, for
those methods that use the GSS-API-authenticated Diffie-Hellman key
exchange algorithm described in Section 2.1, including any future
methods that use different groups and/or hash functions. The intent
is that the names for any such future methods be defined in a similar
manner to that used in Section 2.3.