26 Dec 2002. Daniel Hellerstein (danielh@crosslink.net)

        The SREhttp/2 DYNamic PassWorD facility


1) Abstract:

SREH2_DYNAMIC_PWD is an SREhttp/2 procedure designed to be used by 
SREhttp/2 addons. Its purpose is to provide "digest" style authentication 
to http/1.0 browsers (i.e.; Netscape 4.n and below). It can also be used
to provide a second layer of security (in addition to checking a username and
password).

As opposed to "basic" authentication, SREhttp/2 dynamic password facility
(as well as http/1.1's  "digest" authentication) never sends a user's password 
in the clear.  Instead, a strongly encrypted version of the password is sent, 
an encryption that  changes from session to session (that is, from day to day 
and from IP-address to IP-address).

This encryption does NOT extend to the contents of the request, hence
SREhttp/2's dynamic passwords (as well as http/1.1's "digest" authentication")
is not as powerful as  SSL. Nevertheless, by keeping the password secret 
from prying eyes, most "man in the middle" attacks can be prevented.

  If you are interested in encryption of responses, please see
  ENCRYPT.HTM for a description of SREhttp/2's encryption facility.
      

2) Usage:

First, to use SREH2_DYNAMIC_PWD, you should have:

   A copy of the DYNPWD.RSP "response file" in the SREHTTP2\PROCS directory.

       When installed, SREhttp/2 places DYNPWD.RSP and DYNPWD2.RSP
       in the SREHTTP2\PROCS directory.
       DYNPWD2.RSP is a verbose response file, that contains a 
       technical description of how dynamic-passwords work.

   Actually, your addon can tell SREH2_DYNAMIC_PWD to use
   a different "response" file. For example, the TESTDYN.CMD program
   uses SREHTTP2\PROCS\TESTDYN.RSP.

Using dynamic-passwords requires two steps:

  a) grant "application specific, secret privileges" to your lucky clients.

     For example, TESTDYN.CMD, a sample program provided with SREhttp/2,
     uses SREH2_DYNAMIC_PWD to  control access to files. To use TESTDYN,
     you could have an entry (in a possibly host-specific USERS.CFG file) that 
     defines:
             user = JOE
         password = THEMAN
    and a privset = PRIV1 ?TESTDYN:venus_3
     
    Note that in:  ?TESTDYN:venus_3 
      1) the "?" signals that this is a secret-privilege
      2) the "TESTDYN:" means "this secret privilege is used by 
         the TESTDYN addon".
      3) the  "venus_3" is the shared-secret granted to JOE when using TESTDYN
 
    Hence, JOE should be told that his "shared-secret" is "venus_3".
    
  b) Write an appication that requires dynamic passwords (for example, 
     TESTDYN.CMD). This is actually quite easy, it just requires one 
     call to SREH2_DYNAMIC_PWD.

  c) Optional -- customize DYNPWD.RSP. This is strictly optional -- the
                 generic version of DYNPWD.RSP should work without
                 any modification.

2) Syntax of SREH2_DYNAMIC_PWD

To enable dynamic passwords, you must write an "SREhttp/2" addon that
calls the SREH2_DYNAMIC_PWD procedure.

The calling syntax for SREH2_DYNAMIC_PWD is:

  resp=sreh2_dynamic_pwd(appname,newlocation,privset2,,
                         duration,respfile,nonce,amess,id_info,this_flag)

where:

  appname: recommended. the "application" calling this. Used to identify 
           a "shared secret". It should match whatever you use, in USERS.CFG,
           to identify secret-privileges to use for this addon.

           If not specified, a value of DYNPWD is used.

           Note that APPNAME is also displayed to the client when
           he is asked to provide a shared-secret.

  newlocation: optional. The uri to invoke when client hits the submit
               button. By default, the URI that caused the addon to be
               invoked will be used.

  privset2 : REQUIRED. the space delimited list of "secret" privileges, as
             provided to the addon in the PRIVSET argument. 
             Actually, the "secret" privileges are the subset of the PRIVSET 
             occurring after a comma. Thus:
                  parse var privset . ',' privset2
             can be used to obtain the value of privset2.
             SREH2_DYNAMIC_PWD will look in privset2 for an entry of the
             form "appname:shared_secret" (without the quotes).

             Note that the "secret privileges" listed in privset2 do NOT have
             a leading "?".
                
  pwd_duration: optional. duration of the dynamic password, 
                in days (and fractions of day) (default value is 1 day)

  respfile: optional. A "response file". The response file, which contains 
            javascript and HTML FORM elements, will ask the user to
            provide a shared-secret. It will then create a session key from
            this shared secret (and other information), and send the
            session key back to the server.

            If a fully qualified file name is not given, then a file
            relative to the SREHTTP2\PROCS directory will be used.

            If not specified, DYNPWD.RSP, in SREHTTP2\PROCS, is used.

            NOTE: SREhttp/2 installs a copy of DYNPWD.RSP (and DYNPWD2.RSP)
                  in the SREHTTP2\PROCS directory.

  nonce: optional. Extra information to use when making a session-key.
                   This should NOT change across different requests by the same
                   client, but should change across different clients.  
                   If not specified, the client's IP address is used.

  amess:  An optional string that will be inserted into the response (use
          it for descriptive purposes). Typically this is left blank,
          and SREH2_DYNAMIC_PWD displays current status information.

  id_info: optional. If available, this can speed up processing a bit.

  this_flag  : a unique string (ie; the client's username)

and

  RESP:

      resp='' 
         if a valid password is found

      resp= resp='200 '||length(response) 
        if no valid password is found, 
        sreh2_dynamic_pwd asks the client to supply one --
        resp is the response code for this "response"

      resp=this_flag
         returned if some special action is needed; such as if a "relogon"
         was requested.


Thus, if SREH2_DYNAMIC_PWD returns a '', the client is legit.

If it returns the value of this_flag, then some special action
is required (i.e.; a new Authorization response should be sent).
Exactly what is done is up to the calling procedure.

Anything else means that SREH2_DYNAMIC_PWD has sent a "please
enter shared-secret" response, and has closed the connection.



3) Notes

  * Shared-secrets are case INSENSITIVE.

  * This "please enter a shared-secret" response will 
    continue to be returned until a valid shared-secret is entered,
    or until a special action leads to the this_flag being returned.

    This "special action" is up to the response file. For example,
    DYNPWD.RSP has a "re logon" checkbox -- clicking it causes
    this_flag to be returned. A calling procedure that uses DYNPWD.RSP
    should use the client's username (as extracted using SRE_EXTRACT_USERNAME)
    as the this_flag. Then..
        if the value returned by SREH2_DYNAMIC_PWD equals this_flag, 
        the addon should issue an authorization request.

  * SREhttp/2's dynamic-passwords is implemented by using cookies.
    Once a dynamic password is set, it will be sent on all requests
    to your server. Hence, a one-time "dynamic password logon" is good
    for a day of browsing resources requiring this secret privilege.

  * The use of dynamic passwords can be in addition to the normal access-
    controls of SREhttp/2 (that is, access controls based on required and
    client privileges, as specifed in the ATTRIBS.CFG and USERS.CFG 
    respectively).

  * sreh2_dynamic_pwd uses the respfile to ask the client to supply a 
    "shared-secret" password.

  * For an example of SREH2_DYNAMIC_PWD, see the SREhttp/2 TESTDYN.CMD addon.

  * For further discussion of "secret privileges", see the USERS.HTM.

  * The "privset" argument (to SREhttp/2 addons) is divided into
    two sections: the "normal" privileges (that may be reported
    by the STATUS, and other, addons), and the "secret" privileges
    (that should NEVER be reported by any SREhttp/2 addon).

    To obtain them, use:
         parse var privset privset_normal ',' privset_secret

4) Example of using SREH2_DYNAMIC_PWD in an ADDON

This routine, check_privs, would be called early in your "MY_ADDON" addon.
When check_privs returns ' ', the client has been granted access.
Otherwise, the addon should return RESULT to SREhttp/2 -- 
RESULT it either contains instruction on what SREhttp/2 should do next 
(such as "send an authorization response") or it contains the response 
code from a response sent by SREH2_DYNAMIC_PWD

        ------------ begin example --------------

   call check_privs
   res1=result
   if res1<>'' then return res1  /* otherwise, success! */
        ....  
        .... the body of your addon 
        ....
   exit          /* end of main body */

   check_privs:

   /* first check for SUPERUSER privileges (or some other privilege) */
   if wordpos('SUPERUSER',privset)=0 then do
     if aiter='' then return 'PRIVS This addon requires superuser privileges '
     return 'AUTH This addon requires requires superuser privileges '
   end 

  /* now check for the secret privilege */
   parse var privset . ',' privset2
   authh=sre_reqfield('Authorization')
   uname=sre_extract_username(authh)
   this_flag='RELOGON:'||uname
   resp=sreh2_dynamic_pwd('MY_ADDON',,privset2,0.1,,,,id_info,this_flag) 

   if resp=this_flag then do
       return 'AUTH Please logon as a user other then <tt> 'uname '</tt>'
   end 

   if resp<>''  then do
      return resp
   end 

   return  ' '          /* where ' ' signals "success" */

        ------------ end example --------------

