Request for allocation of new security type code for SASL auth

Daniel P. Berrange berrange "at" redhat.com
Sun Dec 14 16:55:02 2008


I have defined a mapping of the SASL authentication scheme into the RFB
authentication protocol. Please could you allocate an official security
type code for use with this auth scheme, under the name "SASL".

There are a number of reasons why it is desirable to support SASL in
the RFB protocol

 - It is an official internet RFC with API support across all OS platforms,
   providing for both authentication and session data encryption.

 - The SASL protocol is independant of authentication mechanism allowing
   new mechanisms to be plugged in without any application code changes

 - The DIGEST-MD5 SASL mechanism will provide a simple username+password
   based alternative to the existing "VNC" security type, but with stronger
   security, and session data encryption.

 - The GSSAPI SASL mechanism will provider integration with Kerberos for
   Single-Sign-On capabilities, again also having session data encryption

There are a variety of other plugins that will be useful to many people
such as passwd auth against a SQL database,  auth against LDAP, one-time
passwords, and NTLM.

I intend to implement client side support for this "SASL" security type
in the GTK-VNC client, the GNOME VINO server (remote desktop), and the
QEMU built-in VNC server (OS virtualization).

My current security type protocol spec documentation follows, though I may
well refine details of it as I finish the implementations. I currently
have GTK-VNC and QEMU operational, without session encryption.

NB, the protocol description that follows, just picks security code 100
out of the hat. This will obviously be updated to reflect the actual 
security type code officially allocated.

Daniel

6.2.100 SASL Authentication
===========================

SASL authentication is to be used, optionally with a encryption
capability for the protocol data to be negotiated between the
client and server. The author recommends that an SSF layer always
be requested during negotiation unless it is known that the
connection is secured by a prior authentication exchange such as
TLS / VeNCrypt, or externally via a SSH tunnel.

The SASL negotiation is a multi-step protocol, initiated by the
server. The precise number of steps required for the complete
negotiation is determined by the SASL mechanism chosen for auth.
Compliant implementations must expect an arbitrary number of
steps.

The SASL protocol is defined in RFC 2222. Recommended libraries
for implementation on either client or server end are Cyrus-SASL
and gSASL.


6.2.100.1 SASL server initialization message
--------------------------------------------

The server initializes the SASL authentication process by sending
the list of mechanisms it is prepared to accept from the client.

 # of bytes       | Type     | Description
 -----------------+----------+------------------------
  4               | u32      | mechlist-length
  mechlist-length | u8 array | mechlist-string
 -----------------------------------------------------

The "mechlist-string" is a list of SASL mechanism names, each
separated by a comma. The "mechlist-length" is the number of
characters in the string. The trailing '\0' is not transmitted
on the wire. Some example "mechlist-string" values are

    "DIGEST-MD5,GSSAPI"
    "ANONYMOUS,KERBEROS_V4,DIGEST-MD5"

The "mechlist-string" is typically generated on the server by
a call to the function:

    err = sasl_listmech(vs->saslconn,
                        NULL,
                        "",  /* Prefix */
                        ",", /* Separator */
                        "",  /* Suffix */
                        &mechlist,
                        NULL,
                        NULL);

The library used for the SASL implementation will usually
provide a means for the adminsitrator to configure exactly
what mechanisms are enabled.


6.2.100.2 SASL client start message
-----------------------------------

Upon receiving the list of mechanisms allowed by the server,
the client may choose a specific mechanism from the list, or
allow the SASL library to make the choice.

The client shall call "sasl_client_start" providing either
a specific mechanism name, or the full list supported by the
server. The client shall normally supply a list of prompts
it is prepared to support for collecting credentials from
the user.

If the "sasl_client_start" call is successfull, the returned
"clientout" data will need to be sent to the server.


 # of bytes       | Type     | Description
 -----------------+----------+------------------------
 4                | u32      | mechname-length
 mechname-length  | u8 array | mechname-string
 4                | u32      | clientout-length
 clientout-length | u8 array | clientout
 -----------------------------------------------------

The distinction between NULL and "" (empty string) is critical
to preserve. Thus the "clientout-length" will specify the length
of the "clientout" data INCLUDING the trailing '\0', such that
the empty string has "clientout-length" equal to 1, while NULL
data will be transmitted with "clientout-length" equal to 0.

The "mechname-string" is the mechanism name chosen by the client
from the list of advertised mechanisms from the server. The data
sent does not include the trailing '\0' character. Upon receiving
the chosen "mechname-string" from the client, the server shall
validate that it was one of the mechanisms originally advertised
to the client.

Given a successfull call

     sasl_client_start(saslconn,
                       mechlist,
                       &interact,
                       &clientout,
                       &clientoutlen,
                       &mech);

When sending the server reply the following logic is compliant
with the wire protocol


      write_u32(strlen(mech))
      write_u8(mech, strlen(mech))

      if (clientout != NULL) {
         write_u32(strlen(clientout) + 1)
         write_u8(clientout, strlen(clientout) + 1)
      } else {
         write_u32(0)
      }

The client shall now wait for a "6.2.100.3 server start" message

6.2.100.3 SASL server start message
-----------------------------------

Upon receiving the client start message, the server shall validate
that the chosen mechanism was amongst those originally advertised
to the client. It shall now call the "sasl_server_start" API passing
the "clientin" data received from the client, taking care to
preserve the NULL vs "" distinction when de-serializing.

If the "sasl_server_start" call is successfull, the returned
"serverout" data will need to be sent to the server.


 # of bytes       | Type     | Description
 -----------------+----------+------------------------
 4                | u32      | serverout-length
 serverout-length | u8 array | serverout
 1                | u8       | continue
 -----------------------------------------------------

The distinction between NULL and "" (empty string) is critical
to preserve. Thus the "serverout-length" will specify the length
of the "clientout" data INCLUDING the trailing '\0', such that
the empty string has "serverout-length" equal to 1, while NULL
data will be transmitted with "serverout-length" equal to 0.

If the "sasl_server_start" method indicates that further steps
in the negotiation process are required, the "continue" value
shall be 1, otherwise upon succesful completion, or failure of
authentiction it shall be 0.

Given a call to

    err = sasl_server_start(saslconn,
                            mechname,
                            &clientin,
                            &clientinlen,
                            &servertout,
                            &serveroutlen);

When sending the server reply the following logic is compliant
with the wire protocol

    if (err == SASL_OK or err == SASL_CONTINUE) {
      if (serverout != NULL) {
         write_u32(strlen(serverout) + 1)
         write_u8(serverout, strlen(serverout) + 1)
      } else {
         write_u32(0)
      }
      if (err == SASL_OK)
         write_u8(0)
      else
         write_u8(1)
   } else {
      write_u8(0)
      write_u8(0)
   }


If "continue" is zero, then the server protocol continues to
"6.2.100.7 server security check". Otherwise the protocol
continues with "6.2.100.4 SASL client step" message.


6.2.100.4 SASL client step message
----------------------------------

Upon receiving a "6.2.100.3 server start" message, or a
"6.2.100.5 server step" message, the client shall call the
"sasl_client_step" providing the "serverin" data received.

A compliant client shall be prepared to receive 0 or more
"6.2.100.5 server step" messages, as required by the activated
security mechanism.

If the "sasl_client_step" call is successfull, and the previously
received "6.2.100.3 sever start' or "6.2.100.5 server step"
message had the "continue" value set to 0, the client protocol
continues to 6.2.100.6 client security check". The final call
to "sasl_client_step" is important for the client to validate
that the server was truthful in indicating that authentication
was complete.

If the "continue" value was 1, the "clientout" data from the
"sasl_client_step" API call will need to be sent to the server.


 # of bytes       | Type     | Description
 -----------------+----------+------------------------
 4                | u32      | clientout-length
 clientout-length | u8 array | clientout
 -----------------------------------------------------

The distinction between NULL and "" (empty string) is critical
to preserve. Thus the "clientout-length" will specify the length
of the "clientout" data INCLUDING the trailing '\0', such that
the empty string has "clientout-length" equal to 1, while NULL
data will be transmitted with "clientout-length" equal to 0.

Given a successfull call

     sasl_client_step(saslconn,
                      &serverin,
                      &serverinlen,
                      &clientout,
                      &clientoutlen)

And a continue value of '1', when sending the server reply the
following logic is compliant with the wire protocol

      if (clientout != NULL) {
         write_u32(strlen(clientout) + 1)
         write_u8(clientout, strlen(clientout) + 1)
      } else {
         write_u32(0)
      }

The client shall now wait for a "6.2.100.5 server step" message


6.2.100.5 SASL server step message
----------------------------------

Upon receiving the client step message, the shall validate that
the chosen mechanism was amongst those originally advertised to
the client. It shall then call the "sasl_server_step" API passing
the "clientin" data received from the client, taking care to
preserve the NULL vs "" distinction when de-serializing.

If the "sasl_server_step" call is successfull, the returned
"serverout" data will need to be sent to the server.


 # of bytes       | Type     | Description
 -----------------+----------+------------------------
 4                | u32      | serverout-length
 serverout-length | u8 array | serverout
 1                | u8       | continue
 -----------------------------------------------------

The distinction between NULL and "" (empty string) is critical
to preserve. Thus the "serverout-length" will specify the length
of the "clientout" data INCLUDING the trailing '\0', such that
the empty string has "serverout-length" equal to 1, while NULL
data will be transmitted with "serverout-length" equal to 0.

If the "sasl_server_step" method indicates that further steps
in the negotiation process are required, the "continue" value
shall be 1, otherwise upon succesful completion, or failure of
authentiction it shall be 0. If "continue" is zero, then the
protocol continues with "6.2.100.7 server security check"

Given a call to

    err = sasl_server_step(saslconn,
                           &clientin,
                           &clientinlen,
                           &servertout,
                           &serveroutlen);

When sending the server reply the following logic is compliant
with the wire protocol

    if (err == SASL_OK or err == SASL_CONTINUE) {
      if (serverout != NULL) {
         write_u32(strlen(serverout) + 1)
         write_u8(serverout, strlen(serverout) + 1)
      } else {
         write_u32(0)
      }
      if (err == SASL_OK)
         write_u8(0)
      else
         write_u8(1)
   } else {
      write_u8(0)
      write_u8(0)
   }


If "continue" is zero, then the server protocol continues with the
"6.2.100.7 server security check". Otherwise the protocol continues
with another "6.2.100.4 SASL client step" message.


6.2.100.6 SASL client result check
----------------------------------

At this point the client and server have completed the SASL negotiation
process. If the client had requested an SSF layer during its initial
it should now validate that a suitable SSF layer was negotiated with
the server. If the SSF layer is unsuitable it shall drop the connection
to the server.

If the SSF layer is enabled, and suitable for the client, all future
messages transmitted over the RFB protocol shall be passed through
the "sasl_encode" API, and all messages received from the server
AFTER the forthcoming "6.1.3 SecurityResult" shall be passed through
"sasl_decode".

The client now proceeds to wait for "6.1.3 SecurityResult", to determine
whether the server considers the negotiation successful.


6.2.100.7 SASL server result check
----------------------------------

At this point the client and server have completed the SASL negotation
process.

If the SASL negotiation indicated that the client failed to correctly
authenticate, it shall send "6.1.3 SecurityResult" message indicating
that the authentication has fialed and then drop the connection.

The client and server are now authenticated, but before continuing, if
the server had requested an SSF layer during its initial it should
now validate that a suitable SSF layer was negotiated with the client.
If the SSF layer is unsuitable it shall send a "6.1.3 SecurityResult"
message indicating that authentication has failed and then drop the
connection to the client.

If the SSF layer is enabled, and suitable for the client, all messages
transmitted over the RFB protocol AFTER the "6.1.3 SecurityResult"
message shall be passed through the "sasl_encode" API, and all messages
received from the client shall be passed through "sasl_decode".

The server proceeds to send the "6.1.3 SecurityResult" message indicating
succesfull authentication.


-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|