As I promised a long time ago, here is my counter proposal for
generic authentication in ssh. Comments are welcome...
Also, how do I go about submitting this as a draft under the
auspices of the ssh working group? Is it just a matter of
titling it "draft-ietf-secsh-xxx"? I'd prefer to put it
under the working group instead of just an independent draft.
[What is presented here is just the protocol workings, not the
complete text of the proposed draft, which contains an abstract
and other sections. I do still need to add a section that notes
this method is only appropriate for interactive authentications.]
I will post a URL to my ssh1 implementation of the below in a
few days.
~frank
Discussion
Currently defined authentication methods for SSH are tightly coupled
with the underlying authentication mechanism. This makes it
difficult to add new mechanisms for authentication as all clients
must be updated to support the new mechanism. With the generic
method defined here, clients will not require code changes to support
new authentication mechanisms, and if a separate authentication layer
is used, such as [PAM], then the server may not need any code changes
either.
This presents a significant advantage to other methods, such as the
"password" method, as new (presumably stronger) methods may be added
"at will" and system security can be transparently enhanced.
Protocol Exchanges
The authentication starts with the client sending the following
packet (following the packet description conventions used in [SSH-
USERAUTH]):
byte SSH_MSG_USERAUTH_REQUEST
string username
string service
string "password-plus"
Note that when this message is sent to the server, the client has not
yet prompted the user for a password, and so that information is NOT
included with this initial message (unlike the "password" method).
The server MUST reply with either a SSH_MSG_USERAUTH_SUCCESS,
SSH_MSG_USERAUTH_FAILURE, or SSH_MSG_USERAUTH_INFO_REQUEST message.
The server SHOULD NOT reply with the SSH_MSG_USERAUTH_FAILURE message
if the failure is based on the username or service, instead it SHOULD
send a SSH_MSG_USERAUTH_INFO_REQUEST message requesting a password,
and then send the failure message.
The format of the SSH_MSG_USERAUTH_INFO_REQUEST message is as
follows:
byte SSH_MSG_USERAUTH_INFO_REQUEST
boolean name present
string name (if name present is TRUE) (ISO-10646 UTF-8)
boolean banner present
string banner (if banner present is TRUE) (ISO-10646 UTF-8)
int num prompts
string prompt[0] (ISO-10646 UTF-8)
boolean echo[0]
...
string prompt[n] (ISO-10646 UTF-8)
boolean echo[n]
string language tag (as defined in RFC 1766)
The server SHOULD limit the length of the name and prompt fields to
30 characters.
Upon receiving the request message, the client should prompt the user
as indicated.
A CLI client SHOULD simply print the name and banner, followed by
each prompt in turn, to obtain the requested authentication
information. The client is responsible for adding newlines to the
name and banner. A CLI client SHOULD NOT add any additional
characters to the prompt such as ": "; the server is responsible for
supplying all text to be shown to the user.
A GUI client SHOULD present a dialog window, using the name (if
supplied) as the title of the window, the banner (if supplied) as a
text message inside the dialog, and the appropriate number of entry
fields with the prompts as labels. A GUI client MUST properly handle
banners with embedded newlines. A GUI client MUST also be able to
display at least 30 characters for the name and prompts. If the
server presents names/prompts longer than 30 characters, the client
MAY truncate these fields to the length it can display.
For each prompt, the echo field indicates whether or not the user
input should be echoed as characters are typed. Clients MUST
correctly echo/mask user input for each prompt independently of other
prompts in the request message. Clients must also accept empty
responses from the user and pass them on as empty strings.
After obtaining the requested information from a user, the client
MUST respond with a SSH_MSG_USERAUTH_INFO_RESPONSE message:
byte SSH_MSG_USERAUTH_INFO_RESPONSE
int num responses
string response[0] (ISO-10646 UTF-8)
...
string response[n] (ISO-10646 UTF-8)
Note that the responses are encoded in ISO-10646 UTF-8. It is up to
the server how it interprets the responses and validates them.
However, if the client reads the responses in some other encoding
(e.g., ISO 8859-1), it MUST convert the responses to ISO-10646 UTF-8
before transmitting, and the server MUST convert the responses to the
encoding used on that system that is needed to verify them.
Upon receiving the response, the server MUST send a
SSH_MSG_USERAUTH_FAILURE message if the number of responses is not
the same as the number of prompts, or if validation of the responses
fails.
If validation of the responses is successful, and no further
information is needed from the user, the server MUST respond with a
SSH_MSG_USERAUTH_SUCCESS message.
The server may also initiate another request/response cycle (as many
times as needed) if more information is required from the user to
authenticate him (e.g., if the user's password has expired).
Authentication Example
Here is an example exchange between a client and server:
C: byte SSH_MSG_USERAUTH_REQUEST
C: string "foo"
C: string "ssh-connection"
C: string "password-plus"
S: byte SSH_MSG_USERAUTH_INFO_REQUEST
S: boolean TRUE
S: string "Password Authentication"
S: boolean TRUE
S: string "Enter password for foo"
S: int 1
S: string "Password: "
S: boolean FALSE
S: string "en-US"
[Client prompts user for password]
C: byte SSH_MSG_USERAUTH_INFO_RESPONSE
C: int 1
C: string "bar"
S: byte SSH_MSG_USERAUTH_INFO_REQUEST
S: boolean TRUE
S: string "Password Expired"
S: boolean TRUE
S: string "Your password has expired."
S: int 2
S: string "Enter new password: "
S: boolean FALSE
S: string "Enter it again: "
S: boolean FALSE
S: string "en-US"
[Client prompts user for new password]
C: byte SSH_MSG_USERAUTH_INFO_RESPONSE
C: int 2
C: string "baz"
C: string "baz"
S: byte SSH_MSG_USERAUTH_SUCCESS