From c037b6bb40512b75790aa3a11c560a349e451287 Mon Sep 17 00:00:00 2001 From: Barry Jaspan Date: Wed, 16 Oct 1996 15:34:07 +0000 Subject: copied from OV, added init_arg version 4 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@9181 dc483132-0cff-0310-8789-dd5450dbe970 --- doc/rpc/design.tex | 1037 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1037 insertions(+) create mode 100644 doc/rpc/design.tex (limited to 'doc/rpc/design.tex') diff --git a/doc/rpc/design.tex b/doc/rpc/design.tex new file mode 100644 index 000000000..0ccee4707 --- /dev/null +++ b/doc/rpc/design.tex @@ -0,0 +1,1037 @@ +\documentstyle[fullpage,12pt]{article} + +\title{GSS-API Extensions to Sun RPC} +\date{Draft---\today} +\author{Barry Jaspan} + +\setlength{\parskip}{.7\baselineskip} +\setlength{\parindent}{0pt} + +\makeatletter +\newcount\savecnt\savecnt=0 +\def\saveenum#1{\global\savecnt=\csname c@enum#1\endcsname} +\def\restoreenum#1{\csname c@enum#1\endcsname=\savecnt} +\makeatother + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Make _ actually generate an _, and allow line-breaking after it. +\let\underscore=\_ +\catcode`_=13 +\def_{\underscore\penalty75\relax} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{document} + + +{\setlength{\parskip}{0pt}\maketitle\tableofcontents} + +\section{Introduction} + +This document describes the integration of GSS-API authentication and +security with Sun RPC. + +\section{Requirements} + +The requirements of the GSS-API authentication system for Sun RPC are: + +\begin{enumerate} +\item It must provide mutual authentication between RPC clients and +servers. + +\item It must provide for integrity checking and encryption of all +procedure arguments and results passed over the network. +\saveenum{i} +\end{enumerate} + +The following features are desired, but not mandatory: + +\begin{enumerate} +\restoreenum{i} +\item It should provide for integrity checking and encryption of all +``header information'' that specifies the program and procedure being +called. + +\item It should obey the Sun RPC protocol so that clients using +it can interoperate with existing servers. In this case, +``interoperate'' means that existing servers will return an error code +indicating that they do not understand the authentication flavor, but +not that they do not understand the request at all. + +\item It should require minimal or no changes to the standard Sun RPC +programming paradigm for either clients or servers so that existing +code can use it with little or no effort. + +\item It should operate correctly with all the standard Sun RPC +transport mechansims (e.g. UDP and TCP). +\saveenum{i} +\end{enumerate} + +\section{Functional Specification} + +This section describes the programmer's interface to the GSS-API +authentication flavor. Knowledge of standard Sun RPC programming is +assumed. + +\subsection{Client Side} + +A RPC client can select the GSS-API authentication flavor in the same +way it can select any other authentication flavor, by setting the +cl_auth field of the CLIENT structure to the appropriate value: + +\begin{verbatim} + clnt = clnt_create(server_host, PROG_NUM, PROG_VERS, protocol); + clnt->cl_auth = auth_gssapi_create(clnt, ...); +\end{verbatim} + +There are two functions that create GSS-API authentication flavor +structures for the cl_auth field, auth_gssapi_create and +auth_gssapi_create_default. + +\begin{verbatim} +AUTH *auth_gssapi_create(CLIENT *clnt, + OM_uint32 *major_status, + OM_uint32 *minor_status, + gss_cred_id_t claimant_cred_handle, + gss_name_t target_name, + gss_OID mech_type, + int req_flags, + int time_req, + gss_OID *actual_mech_type, + int *ret_flags, + OM_uint32 *time_rec); +\end{verbatim} + +auth_gssapi_create creates a GSS-API authentication structure and +provides most of the flexibility of gss_init_sec_context. The +arguments have the same interpretation as those of +gss_init_sec_context with the same name, except: + +\begin{description} +\item[clnt] The CLIENT structure returned by client_create or one of +its relatives. It is not modified. +\end{description} + +auth_gssapi_create calls gss_init_sec_context as needed, passing each +generated token to and processing each token returned from the RPC +server specified by the RPC handle clnt. On return, if major_status +is GSS_S_COMPLETE, the context has been established, the returned AUTH +structure is valid, and all of the arguments filled in by +gss_init_sec_context have the correct values. If major_status is not +GSS_S_COMPLETE then it and minor_status contain error codes that can +be passed to gss_display_status and the returned value is NULL. + +\begin{verbatim} +AUTH *auth_gssapi_create_default(CLIENT *clnt, char *service_name); +\end{verbatim} + +auth_gssapi_create_default is a shorthand for auth_gssapi_create that +attempts to create a context that provides procedure call and result +integrity, using the default credentials and GSS-API mechanism. +service_name is parsed as a GSS-API ``service'' name and used as the +target name. The other arguments to auth_gssapi_create are as follows: + +\begin{verbatim} +auth_gssapi_create(clnt, + &dummy, + &dummy, + GSS_C_NO_CREDENTIAL, + target_name, + GSS_C_NULL_OID, + GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, + 0, + NULL, + NULL, + NULL); +\end{verbatim} + +Note that if the underlying default mechanism does not support data +integrity (e.g. the trust mechanism), this function will fail. + +The GSS-API major and minor status codes can be interpreted with +auth_gssapi_display_status: + +\begin{verbatim} +void auth_gssapi_display_status(char *msg, OM_uint32 major, + OM_uint32 minor); +\end{verbatim} + +All of the error messages associated with the major and minor status +are displated on the standard error output, preceeded by the message +``GSS-API authentication error $<$msg$>$:''. + +\subsection{Server Side} + +\subsubsection{Service Name Registration} + +An application server must register the service name(s) that it will +use for GSS-API connections before any AUTH_GSSAPI requests will +succeed. + +\begin{verbatim} +typedef struct _auth_gssapi_name { + char *name; + gss_OID type; +} auth_gssapi_name; + +bool_t _svcauth_gssapi_set_names(auth_gssapi_name *names, int num); +\end{verbatim} + +names is an array of name specifications, each of which consists of a +null-terminated ASCII representation of a name and the GSS-API name +type that should be used to import it with gss_import_name. The +name type ``gss_nt_service_name'' is recommended. + +\subsubsection{Calling Client and Service Identification} + +Each application server's dispatch function is passed two arguments, +the transport mechanism (transp) and the RPC service request (rqstp). +If the service request's credential flavor (rq_cred.oa_flavor) is +AUTH_GSSAPI (300001)\footnote{The value 4 was originally used, but +300001 has been officially assigned by the IETF.}, then the call has +been authenticated. The rq_clntcred field of transp contains the +gss_name_t of the authenticated caller and can be passed to +gss_display_name to obtain a string represtation or gss_compare_name +to compare it with other names. The rq_svccred field of transp +contains the GSS-API context established with the caller and can be +passed to gss_inquire_context. + +\subsubsection{Error Logging} + +An application server can register a function to be called when a +failure occurs during GSS-API context establishment with +_svcauth_set_log_badauth_func. + +\begin{verbatim} +typedef void (*auth_gssapi_log_badauth_func)(OM_uint32 major, + OM_uint32 minor, + struct sockaddr_in *raddr, + caddr_t data); + +void _svcauth_set_log_badauth_func(auth_gssapi_log_badauth_func func, + caddr_t data); +\end{verbatim} + +The function func is called each time gss_accept_sec_context fails. +The major and minor arguments indicate the GSS-API major and minor +status codes returned. The raddr field contains the INET socket that +the request came from, and the data field contains the data argument +of _svcauth_gssapi_set_log_badauth_func. + +An application server can register a function to be called when an RPC +request with an invalid verifier arrives with +_svcauth_set_log_badverf_func. + +\begin{verbatim} +typedef void (*auth_gssapi_log_badverf_func)(gss_name_t client, + gss_name_t server, + struct svc_req *rqst, + struct rpc_msg *msg, + caddr_t data); + +void _svcauth_set_log_badverf_func(auth_gssapi_log_badverf_func func, + caddr_t data); +\end{verbatim} + +The function specified in func is called each time an invalid verifier +is received. The client and server fields identify the (falsely +claimed) originating client and the server it originally authenticated +to. The raddr and addrlen fields contain the INET socket that the +request (claims to have) come from, and data contains the data +argument of _svcauth_set_log_badverf_func. + +\section{Modifications to Sun RPC} + +The Sun RPC extensible authentication mechanism is designed to allow +different authentication systems to be integrated into Sun RPC easily. +Unfortunately, it has two drawbacks. First, the existing system has a +number of non-general design properties that are intended specifically +for Sun's Secure RPC, and second, the existing system has no concept +of or ability to perform authentication-flavor-specific operations on +function arguments and results passed over the wire. The first +problem merely makes the system confusing, since a number of features +touted as ``general'' do not make any sense for arbitrary +authentication systems. The second problem is more substantial, and +can only be corrected by modifications to Sun RPC internals. + +The following sections describe the necessary modifications to Sun +RPC. + +\subsection{Client Side Authentication, AUTH Structure} + +The AUTH structure (figure \ref{fig:auth}) encapsulates the data and +function pointers for an authentication flavor instance. It has been +changed in two ways. + +\begin{figure}[htbp] +\begin{verbatim} +typedef struct { + struct opaque_auth ah_cred; + struct opaque_auth ah_verf; + union des_block ah_key; + struct auth_ops { + void (*ah_nextverf)(); + int (*ah_marshal)(); /* nextverf & serialize */ + int (*ah_validate)(); /* validate varifier */ + int (*ah_refresh)(); /* refresh credentials */ + int (*ah_wrap)(); /* encode data for wire */ + int (*ah_unwrap)(); /* decode data from wire */ + void (*ah_destroy)(); /* destroy this structure */ + } *ah_ops; + caddr_t ah_private; +} AUTH; +\end{verbatim} +\caption{The AUTH structure, with the new function pointers ah_wrap +and ah_unwrap.} +\label{fig:auth} +\end{figure} + +First, the new functions ah_wrap and ah_unwrap prepare function +arguments and results for transmission over the wire. The +authentication mechanism can use them to sign, encrypt, or perform any +other operation on the data. Their prototype is: + +\begin{verbatim} +bool_t ah_wrap(AUTH *auth, XDR *out_xdrs, xdrproc_t func, caddr_t ptr); +bool_t ah_unwrap(AUTH *auth, XDR *in_xdrs, xdrproc_t func, caddr_t ptr); +\end{verbatim} + +ah_wrap encodes function arguments for transmission. func and ptr are +the XDR procedure and pointer that serialize the arguments, and +out_xdrs is the xdr stream that the encoded arguments should be +written to. ah_unwrap decodes function arguments received from the +network. Its arguments are the converse of those to ah_wrap. + +It is the responsibility of RPC transport mechanisms to call an +authorization flavor's ah_wrap and ah_unwrap functions when function +arguments or results would normally be written to or read from the +wire. Authorization flavors that do not need to perform any encoding +or decoding can use the provided function authany_wrap for ah_wrap +and ah_unwrap; it consists of the single statement ``return +(*func)(out_xdrs, ptr)'' (or in_xdrs, as appropriate). + +Second, the function ah_refresh has been changed to take the RPC error +message that resulted in its being called as an argument. This is +necessary since the contents of the error message may dictate how +ah_refresh should go about correcting the authentication failure. + +\subsection{Client Side Transport Mechanisms} + +Each client side transport mechanism must be modified to call the +ah_wrap and ah_unwrap functions from the cl_auth field of the CLIENT +structure during the call and reply process. The modification is +fairly simple. For example, the UDP transport mechanism used to +encode procedure calls like this: + +\begin{verbatim} + if ((! XDR_PUTLONG(xdrs, (long *)&proc)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! (*xargs)(xdrs, argsp))) + return (cu->cu_error.re_status = RPC_CANTENCODEARGS); +\end{verbatim} + +The last function call in the conditional serializes the arguments +onto the xdr stream. This must be replaced with a call to the +appropriate ah_wrap function: + +\begin{verbatim} + if ((! XDR_PUTLONG(xdrs, (long *)&proc)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! AUTH_WRAP(cl->cl_auth, xdrs, xargs, argsp))) + return (cu->cu_error.re_status = RPC_CANTENCODEARGS); +\end{verbatim} + +AUTH_WRAP is a macro that takes the four arguments for an ah_wrap +function and extracts and calls the function pointer from the cl_auth +structure with the specified arguments. + +Similarly, the transport mechanism must unwrap procedure results. +Again, the UDP mechanism will be instructive. It used to deserialize +function results like this: + +\begin{verbatim} + reply_msg.acpted_rply.ar_results.where = resultsp; + reply_msg.acpted_rply.ar_results.proc = xresults; + + ok = xdr_replymsg(&reply_xdrs, &reply_msg); +\end{verbatim} + +The problem here is that xdr_replymsg deserializes an entire reply +message, including the results. Since xresults and resultsp are the +function and pointer to decode the results, they will be automatically +deserialized {\it without} ah_unwrap being invoked. The simplest +solution (which is also the normal method used by the TCP mechanism) +is to arrange to deserialize the function results explicitly: + +\begin{verbatim} + reply_msg.acpted_rply.ar_results.where = NULL; + reply_msg.acpted_rply.ar_results.proc = xdr_void; + + if ((! xdr_replymsg(&reply_xdrs, &reply_msg)) || + (! AUTH_UNWRAP(cl->cl_auth, reply_xdrs, xresults, + resultsp))) { + return (cu->cu_error.re_status = RPC_CANTENCODEARGS); + } +\end{verbatim} + +Since xdr_void does not read any data from the XDR stream, the +function results are still available when AUTH_UNWRAP is called. Note +that AUTH_UNWRAP should only be called on {\it successfull} calls; if +the reply message status is not RPC_SUCCESS there are no arguments to +read. + +Currently, the UDP and TCP transport mechanisms has been +converted.\footnote{The ``raw'' mechanism, for direct connections, has +not been.} + +\subsection{Service Side Authentication, SVCAUTH and XPRT} + +Standard Sun RPC service-side authentication consists of a single +function per authentication flavor; there is no concept of an AUTH +structure containing function pointers and private data as with the +client side. Previously, nothing else was necessary, because each +flavor only did a single thing (authenticated individual calls in a +stateless manner). More functions and state are now required, +however; they are stored in the SVCAUTH structure, see figure +\ref{fig:svcauth}. + +\begin{figure}[htbp] +\begin{verbatim} +typedef struct { + struct svc_auth_ops { + int (*svc_ah_wrap)(); + int (*svc_ah_unwrap)(); + } *svc_ah_ops; + caddr_t svc_ah_private; +} SVCAUTH; +\end{verbatim} +\caption{The new SVCAUTH structure.} +\label{fig:svcauth} +\end{figure} + +There is one SVCAUTH structure per authentication flavor (there is a +default, svc_auth_any, for existing authentication flavors that do not +need the extra functionality). The svc_ah_wrap and svc_ah_unwrap +perform the same logical function as their client-side counterparts. + +Just as with the client side, it is the responsibility of the +transport mechanism to call the svc_ah_wrap and svc_ah_unwrap +functions associated with the authentication flavor associated with +each RPC call at the appropriate time. Unfortunately, the transport +mechanism code does not have access to the RPC call structure +containing the authenticator flavor because the RPC call structure +itself is not passed as an argument to the necessary functions. The +present solution is to add another argument to the transport mechanism +structure, xp_auth, that stores the SVCAUTH of the {\it current} call +on that mechanism; see figure \ref{fig:xprt}. xp_auth is initialized +to svc_auth_any so that existing authentication mechanisms that do not +set the field will still operate correctly. \footnote{This is not an +great solution, because it forces each transport mechanism to be +single threaded. The correct solution is to store the SVCAUTH +associated with each RPC call in the RPC call structure; however, +doing so would require changing a lot of code to pass around the RPC +call structure that currently does not do so. Since other parts of +Sun RPC use the XPRT structure in a non-reentrant way, the present +solution does not make the situation any +worse.}$^{\mbox{,}}$\footnote{A somewhat irrelevant side effect of +adding SVCAUTH to XPRT is that the standard include file +$<$rpc/rpc.h$>$ had to be changed to include $<$rpc/svc_auth$>$ before +$<$rpc/svc.h$>$, whereas they used to be in the opposite order.} + +\begin{figure}[htbp] +\begin{verbatim} +typedef struct { + int xp_sock; + u_short xp_port; /* associated port number */ + struct xp_ops { + bool_t (*xp_recv)(); /* receive incomming requests */ + enum xprt_stat (*xp_stat)(); /* get transport status */ + bool_t (*xp_getargs)(); /* get arguments */ + bool_t (*xp_reply)(); /* send reply */ + bool_t (*xp_freeargs)();/* free mem allocated for args */ + void (*xp_destroy)(); /* destroy this struct */ + } *xp_ops; + int xp_addrlen; /* length of remote address */ + struct sockaddr_in xp_raddr; /* remote address */ + struct opaque_auth xp_verf; /* raw response verifier */ + SVCAUTH *xp_auth; /* auth flavor of current req */ + caddr_t xp_p1; /* private */ + caddr_t xp_p2; /* private */ +} SVCXPRT; +\end{verbatim} +\caption{The modified XPRT structure, with the xp_auth field.} +\label{fig:xprt} +\end{figure} + +Finally, with the modified XPRT structure carrying around the +authentication flavor structure, the functions that serialize and +deserialize function arguments and results must be modified to use the +svc_ah_wrap and svc_ah_unwrap functions. Each service-side transport +mechanism has getargs and reply functions that must be modified to use +the SVCAUTH_UNWRAP and SVCAUTH_WRAP macros, respectively, in a manner +completely parallel to the client side. + +\subsection{Authenticated Service Identification, svc_req} + +Sun RPC provides the authenticated credentials of a client to the +application server via rq_clntcred (``cooked credentials'') field of +the service request (svc_req) structure. In many authentication +systems, services are also named entities, and there is no reason that +an RPC should be restricted to accepting connections as a single +authenticated service name. However, access control decisions may be +based on the service name a client authenticated to, so that +information must be available to the application server. + +Figure \ref{fig:svc-req} shows the modified service request structure +that contains a single new field, rq_svccred. Like rq_clntcred, the +authentication flavor is responsible for setting rq_svccred to the +``cooked'' service credentials associated with a given RPC call. +Authentication flavors that do not have the concept of service names +can of course leave this field blank. + +\begin{figure}[htbp] +\begin{verbatim} +struct svc_req { + u_long rq_prog; /* service program number */ + u_long rq_vers; /* service protocol version */ + u_long rq_proc; /* the desired procedure */ + struct opaque_auth rq_cred; /* raw creds from the wire */ + caddr_t rq_clntcred; /* read only cooked client cred */ + caddr_t rq_svccred; /* read only cooked svc cred */ + SVCXPRT *rq_xprt; /* associated transport */ +}; +\end{verbatim} +\caption{The modified svc_req structure, with the rq_svccred field.} +\label{fig:svc-req} +\end{figure} + + + +\subsection{Authentication Negotiation, no_dispatch} + +In order to avoid having to transmit a full set of authentication +information with every call, the service-side authentication mechanism +must save state between calls. Establishing that state may require +multiple messages between the client-side and service-side +authentication mechanisms. The client-side authentication mechanism +can make arbitrary RPC calls to the server simply by requiring the +programmer to specify the CLIENT structure to the authentication +flavor initialization routine. The service side, however, is more +complex. In the normal course of events, an RPC call comes in, is +authenticated, and is then dispatched to the appropriate procedure. +For client- and service-side authentication flavors to communicate +indepedent of the server implemented above the RPC layer, the +service-side flavor must be able to send a reply to the client +directly and {\it prevent} the call from being dispatched. + +This is implemented by a simple modification to the _authenticate +routine, which dispatches each RPC call to the appropriate +authentication flavor; see figure \ref{fig:authenticate}. It takes an +additional argument, no_dispatch, that instructs the mechanism not to +dispatch the RPC call to the specified procedure. + +\begin{figure}[htbp] +\begin{verbatim} + why=_authenticate(&r, &msg, &no_dispatch); + if (why != AUTH_OK) { + svcerr_auth(xprt, why); + goto call_done; + } else if (no_dispatch) { + goto call_done; + } +\end{verbatim} +\caption{A call to the modified _authenticate.} +\label{fig:authenticate} +\end{figure} + +If _authenticate sets no_dispatch to true, the call is considered +finished and no procedure dispatch takes place. Presumably, an +authentication flavor that sets no_dispatch to true also replies to +the RPC call with svc_sendreply. Authentication flavors that do not +modify no_dispatch implicitly leave it set to false, so the normal +dispatch takes place. + +\subsection{Affected Files} + +Table \ref{tab:modfiles} lists the files that were +affected for each of the modifications described in previous sections. + +\begin{table}[htbp] +\centering +\caption{Files modified for each change to Sun RPC.} +\label{tab:modfiles} +\begin{tabular}{ll} +AUTH structure & auth.h \\ + & auth_none.c \\ + & auth_exit.c \\ + & auth_any.c \\ +Client Transport Mechanisms & clnt_udp.c \\ + & clnt_tcp.c \\ +SVCAUTH and XPRT structures & rpc.h \\ + & svc.h \\ + & svc_auth.h \\ + & svc.c \\ + & svc_auth.c \\ + & svc_auth_any.c \\ + & svc_auth_unix.c \\ +Server Transport Mechanisms & svc_udp.c \\ + & svc_tcp.c +\end{tabular} +\end{table} + +\section{GSS-API Authentication Flavor} + +The following sections describe the implemetation of the GSS-API +authentication flavor for Sun RPC. + +\subsection{Authentication Algorithms} +\label{sec:algorithms} + +\subsubsection{Context Initiation} + +The client creates a GSS-API context with the server each time it +calls auth_gssapi_create. The context is created using the standard +gss_init_sec_context and gss_accept_sec_context function calls. The +generated tokens are passed between the client and server as arguments +and results of normal RPC calls. + +The client side, in auth_gssapi_create, performs the following steps +to initiate a context: + +\begin{enumerate} +\item\label{item:process-token} The client calls gss_init_sec_context. +On the first such call, no input token is provided; on subsequent +calls, the token received from the server is provided. + +\item If gss_init_sec_context produces an output token: + +\begin{enumerate} +\item The client transmits the token to the server, identifying itself +with client_handle if it has already been received (see next step). +The return value from the server will contain a client_handle and one +or both of a token and a signed initial sequence number. + +\item If this is the first response from the server, the client_handle +is stored for subsequent calls. Otherwise, the client_handle should be +the same as returned on the previous call. + +\item If the response contains a signed initian sequence number but +the context is not yet established, then the response also contains a +token that will established the context. The signed initial sequence +number is stored. + +\item If the response contains a token, step \ref{item:process-token} +repeated. +\end{enumerate} + +\item The signed initial sequence number is verified using the +established context. +\end{enumerate} + +The server side, in _svcauth_gssapi, performs the following steps to +initiate a context: + +\begin{enumerate} +\item If a call arrives with no client_handle, a new client_handle is +allocated and stored in the database. Otherwise, the client's +previous state is is looked up in the database. + +\item The received token is passed to gss_accept_sec_context. If an +output token is generated, it is returned to the client. Note that +since the application server may have registered multiple service +names and there is no way to determine {\it a priori} which service a +token is for, _svcauth_gssapi calls gss_accept_sec_context once for +each registered credential until one of them succeedes. The code +assumes that GSS_S_FAILURE is the only error that can result from a +credential mismatch, so any other error terminates the loop +immediately. + +\item If the context is established, the server signs an initial +sequence number and returns it to the client. +\end{enumerate} + +Note that these algorithms require context establishment to be +synchronous. If gss_init_sec_context returns GSS_S_COMPLETE upon +processing a token, it will either produce a token or not. If it +does, then gss_accept_sec_context will return GSS_S_COMPLETE when that +token is processed; if it does not, then gss_accept_sec_context +already returned GSS_S_COMPLETE (and presumably returned the token +that caused gss_init_sec_context to return GSS_S_COMPLETE when +processed). The reverse is also true. + +\subsubsection{RPC Calls} + +After the GSS-API context is established, both the server and the +client posess a client handle and a corresponding sequence number. +Each call from the client contains the client handle as the +``credential'' so that the server can identify which context to apply +to the call. + +Each client call and server response includes a ``verifier'' that +contains the sealed current sequence number.\footnote{In a future +version, the verifier will also contain a signature block for the call +header, including the procedure number called.} The sequence number +prevents replay attacks\footnote{Although some GSS-API mechanisms +provide replay detection themselves, not all of them do; explicitly +including the sequence number in the RPC therefore provides better +end-to-end security}, but by itself it does not prevent splicing +attacks. + +Each procedure argument and result block consists of the current +sequence number and the actual serialized argument string, all sealed +with gss_seal. Combining the sequence number with the argument/result +data prevents splicing attacks. + +The sequence number is incremented by one for each RPC call and by one +for each response. The client and server will both reject messages +that do not contain the expected sequence number. Packets +retransmitted by the client should use the {\it same} sequence number +as the original packet, since even if the server receives multiple +copies only one will be honored. + +\subsection{RPC Call Credential Structure} + +Every message transmitted from the client to the server has a +credentials (cb_cred) field of the type auth_gssapi_creds: + +\begin{verbatim} +typedef struct _auth_gssapi_creds { + bool_t auth_msg; + gss_buffer_desc client_handle; +}; +\end{verbatim} + +The auth_msg field indicates whether the message is intended for the +authentication mechanism for the actual server. Any message whose +auth_msg field is true is processed by the authentication mechanism; +any message whose auth_msg is false is passed to the application +server's dispatch function if authentication suceeds. All messages +must have an auth_msg of true until the context is established, since +authentication cannot succeed until it is. + +The client_handle field contains the client handle obtained from the +first call to the server. On the first call, this field is empty. + +\subsection{GSS-API Authentication Flavor Procedures} + +The GSS-API authentication flavor uses standard RPC calls over the +client handle it is provided for the interactions described in +\ref{sec:algorithms}. All of the following procedures require the +auth_msg field in the credentials to be true; otherwise, the +server-side authentication flavor will simply attempt to authenticate +the caller and pass the call to the application server. The +server-side authentication flavor uses the no_dispatch variable to +indicate that it has handled the call. + +\subsubsection{AUTH_GSSAPI_INIT, AUTH_GSSAPI_CONTINUE_INIT} + +Context initiation is performed via AUTH_GSSAPI_INIT and +AUTH_GSSAPI_CONTINUE_INIT. The former is used to transfer the first +token generated by gss_init_sec_context, when no client handle is +included in the credentials; the latter is used on subsequent calls, +when a client handle is included. + +Both procedures take an argument of type auth_gssapi_init_arg and +return results of the type auth_gssapi_init_res. + +\begin{verbatim} +typedef struct _auth_gssapi_init_arg { + u_long version; + gss_buffer_desc token; +} auth_gssapi_init_arg; +\end{verbatim} + +\begin{description} +\item[version] Three versions are presently defined. + +\begin{description} +\item[1] The original version, as described in this document + +\item[2] In earlier versions of Secure there was a bug in the GSS-API +library that affected the contents of accept_sec_context output +tokens. A client specifies version 2 to indicate that it expects the +correct (fixed) behavior. If the server indicates AUTH_BADCRED or +AUTH_FAILED it does not understand this version, so the client should +fall back to version 1. + +\item[3] Version three indicates that channel bindings are in use. +The client must specify channel bindings with the version, and the +server will as well. If the server indicates AUTH_BADCRED or +AUTH_FAILED it does not understand this version, so the client should +fall back to version 2 (and cease specifying channel bindings). + +\item[4] The previous versions all used the old GSS-API krb5 mechanism +oid; this version uses the new one specified in the RFC. +\end{description} + +\item[token] The token field contains the token generated by +gss_init_sec_context. +\end{description} + +\begin{verbatim} +typedef struct _auth_gssapi_init_res { + u_long version; + gss_buffer_desc client_handle; + gss_buffer_desc token; + OM_uint32 gss_major, gss_minor; + gss_buffer_desc signed_isn; +} auth_gssapi_init_res; +\end{verbatim} + +\begin{description} +\item[version] There are two versions currently defined. +\begin{description} +\item[1] The original version, as described in this document. This is +the response version for {\it both} versions 1 and 2. The Secure 1.1 +server will always return this version. + +\item[3] Version three indicates that the server specified channel +bindings in response to a call arg version number of three. The +server must not specify this version unless the client does. +\end{description} + +\item[client_handle] The client_handle field contains the client +handle that the client must use in the credentials field in all +subsequent RPC calls. In response to AUTH_GSSAPI_CONTINUE_INIT, it is +the same client handle that arrived in the credentials. + +\item[gss_major, gss_minor] The GSS-API error codes that resulted from +processing the auth_gssapi_init_arg. If gss_major is GSS_S_COMPLETE, +the argument token was processed successfully. Otherwise, gss_major +and gss_minor contain the relevant major and minor status codes, and +the context currently being negotiated is no longer valid. + +\item[token] In any response that the client is expecting another +token (i.e.: gss_init_sec_context last returned GSS_S_CONTINUE), the +token field contains the output token from gss_accept_sec_context. If +the client is not expecting a token and this field is not empty, an +error has occurred. + +\item[signed_isn] If the client is not expecting another token (i.e.: +the previous call to gss_init_sec_context yielded a token and returned +GSS_S_COMPLETE) or the supplied token completes the context, the +signed_isn field contains the signed initial sequence number. The +server expects the first RPC call to have a sequence number one +greater than the initial sequence number (so that the signed_isn block +cannot be replayed). If the client is expecting another token and the +signed_isn field is not empty, an error has occurred. +\end{description} + +\subsubsection{AUTH_GSSAPI_DESTROY} + +Context tear-down is performed via AUTH_GSSAPI_DESTROY. This +procedure takes no arguments and returns no results; it merely informs +the server that the client wishes to destroy the established context. + +When a client wishes to tear down an established context between +itself and a server, auth_gssapi_destroy first calls the +AUTH_GSSAPI_DESTROY procedure. The server authenticates the message +and immediately sends a ``success'' response with no results. The +client and server then both independently call gss_delete_sec_context +and discard the context-destruction token that is generated. + +No RPC error checking is performed by either the client or the server. +The client waits a brief time for a success response from the server, +but if none arrives it destroys the context anyway since presumably +the user is waiting for the application to exit. The server similar +ignores any RPC errors since it knows that the client will ignore any +errors that are reported. + +\subsection{RPC Call Authentication Implementation} + +Once the context has been established, all subsequent RPC calls are +authenticated via the verifier described in section +\ref{sec:algorithms}. + +auth_gssapi_marshall, invoked via AUTH_MARSHALL while the RPC call is +being created on the client side, serializes the client_handle +obtained during context initiation {\it in plaintext} as the +credentials and serializes the current sequence number, sealed with +gss_seal, as the verifier. + +auth_gssapi_wrap, invoked next via AUTH_WRAP, serializes a sealed +token containing both the sequence number of the current call and the +serialized arguments. + +_svcauth_gssapi, invoked on the server side by _authenticate, uses the +client_handle contained in the credentials to look up the correct +context and verifies the sequence number provided in the verifier; if +the sequence number is not correct, it declares a potential replay +attack.\footnote{Retransmitted packets will appear as replay attacks, +of course.} The response verifier is set to the serialized sealed +incremented sequence number. + +svc_auth_gssapi_unwrap, invoked when either the application server or +_svcauth_gssapi (in response to an AUTH_GSSAPI authentication flavor +message) attempts to read its arguments, deserialzes and unseals the +block containing the current sequence number and serialized arguments. +If the sequence number is incorrect, it declares a splicing attack; +otherwise, it unserializes the arguments into the original structure. + +svc_auth_gssapi_wrap, invoked when either the application server or +_svcauth_gssapi attempts to write its response, performs the same +operation as auth_gssapi_wrap. + +auth_gssapi_validate, invoked by the client-side RPC mechanism when +an RPC_SUCCESS response is received, verifies that the returned sequence +number is one greater than the previous value sent by +auth_gssapi_marshall. + +Finally, auth_gssapi_unwrap, invokved by the client-side RPC mechanism +after auth_gssapi_validate succeeds, performs the same operation as +svc_auth_gssapi_unwrap. + +If an RPC request generates an error message (a status of other than +RPC_SUCCESS), auth_gssapi_refresh is called. If the error status is +AUTH_REJECTEDVERF, then the server rejected the sequence number as +invalid or replayed. The client guesses that, on some previous call, +the server received a message but the server's response did not make +it back to the client; this could happen if the packet got lost or if +the server was being debugged and the client timed out waiting for it. +As a result, the server is expected a higher sequence number than the +client sent. auth_gssapi_refresh increments the sequence number and +returns true so that the call will be tried again. The transport +mechanism will only call auth_gssapi_refresh twice for each RPC +request, so if some other error occurred an infinite loop will not +result; however, it is unlikely the the client and server will be able +to resynchronize after such an event. + +\subsection{Client State Information} + +The client-side GSS-API authentication flavor maintains an +auth_gssapi_data structure for each authentication instance: + +\begin{verbatim} +struct auth_gssapi_data { + bool_t established; + CLIENT *clnt; + gss_ctx_id_t context; + gss_buffer_desc client_handle; + u_long seq_num; + int def_cred; + + /* pre-serialized ah_cred */ + u_char cred_buf[MAX_AUTH_BYTES]; + u_long cred_len; +}; +\end{verbatim} + +The established field indicates whether the authentication context +between the client and server has been established. It is set to true +when gss_init_sec_context returns GSS_S_COM\-PLETE. When this field is +false, the auth_gssapi functions marshall, validate, wrap, and unwrap +mimic the ``no authentication'' flavor since there is no context with +which to perform authentication functions.\footnote{This field is +necessary because, when auth_gssapi_create calls clnt_call to make an +RPC call, it has to have set the client's authentication flavor to +AUTH_GSSAPI; otherwise, the service-side RPC mechanism will not know +to dispatch the call to _svcauth_gssapi. However, with the client's +authentication flavor set, all of the authentication flavor's +functions will be automatically invoked, even though they are not +ready to operate.} + +The clnt field contains the RPC client structure that can be used to +communicate with the GSS-API authentication flavor on the server. + +The context field contains the context structure created by +gss_init_sec_context. + +The client_handle field contains the client handle used on all RPC +calls except the first one; the handle is obtained as the result of +the first call. + +The sequence_number field contains the sequence number that will be +used when transmitting RPC calls to the server and verifing the +server's responses after the context is initialized. + +The def_cred field is true if gss_init_sec_context created a default +credential, in which case the authentication mechanism is responsible +for releasing the default credential that gets automatically +allocated. + +The cred_buf and cred_len fields contain the pre-serialized +credentials structure used in each call. This provides a small +performance enhancement since the credentials structure does not +change very often; the same pre-serialized version can be used on +virtually every call. + +\subsection{Server State Information} +\label{sec:server-state} + +The server-side GSS-API authentication flavor maintains an +svcauth_gssapi_data structure for each established or partially +established context: + +\begin{verbatim} +typedef struct _svc_auth_gssapi_data { + bool_t established; + gss_ctx_id_t context; + gss_name_t client_name, server_name; + gss_cred_id_t server_creds; + + u_long expiration; + u_long seq_num; + u_long key; + + SVCAUTH svcauth; +} svc_auth_gssapi_data; +\end{verbatim} + +The established field indicates whether the context is fully +established. + +The context field contains the context created by +gss_accept_sec_context. + +The client_name field contains the client's authenticated name, as +returned by gss_accept_sec_context. _svcauth_gssapi sets the ``cooked +credentials'' field of the RPC call structure to this value after the +call is authenticated; the application server can use it to perform +authorization. + +The server_name field contains the service name that the client +established a context with. This is useful if the application server +registered more than one service name with the library; it allows the +server to determine which service the client chose. + +The server_creds field contains the service credentials that the +client established a context with. It is used to avoid having to scan +through the server_creds_list multiple times in the case that context +establishment requires more than one round-trip to the server. + +The expiration field contains the expiration time of the context, as a +Unix timestamp. If a context has no expiration (time_rec is +GSS_C_INDEFINITE), the expiration time is set to 24 hours in the +future. When the structure is created, before the context is +established, the expiration time is initialized to small duration +(currently 5 minutes) so that partially created and abandoned contexts +will be expired quickly. + +The seq_num field is the current sequence number for the client. + +The key field is the client's key into the hash table (see below). +The client_handle field sent to the client is the key treated as an +arbitrary four-byte string. + +The svcauth field is a kludge that allows the svc_auth_gssapi +functions to access the per-client data structure while processing a +call. One SVCAUTH structure is allocated for each client structure, +and the svc_ah_private field is set to the corresponding client. The +client's svcauth field is then set to the new SVCAUTH structure, so +that client_data->svcauth->svc_ah_private == client_data. As each +request is processed, the transport mechanism's xp_auth field is set +to the client's svcauth field; thus, the server-side functions that +dispatch to server-side authentication flavors can access an +appropriate SVCAUTH structure, and the server-side authentication +function that is called can determine the appropriate per-client +structure from the SVCAUTH structure. + +The per-client structures are all stored both in a BSD 4.4 db library +hash table and b-tree. The hash table maps client handles (key +fields) the client structures, and is used to look up client +structures based on the client_handle field of a call's credentials +structure. The b-tree stores the client structures as keys, sorted by +their expiration time. Each time _svcauth_gssapi is activated, it +traverses the tree and destroys all client structures that have +expired. + +\end{document} -- cgit