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 'uname '' end if resp<>'' then do return resp end return ' ' /* where ' ' signals "success" */ ------------ end example --------------