Go to the previous, next section.
There are a number of components that make up a successful security
policy for an application based on a distributed object system. Only a
few of them deal with the distributed object system. This document
gives an overview of some of the issues, and explains how they may be
achieved with the mechanisms provided in ILU 2.0. For a fuller
discussion of the issues, see the OMG Security Working Group's white
paper on security, http://www.omg.org/docs/1994/94-04-16.ps
.
There are a number of things which are often lumped under the umbrella of `security'. They include:
Some of these items are more complex than they appear to be at first glance. For example, the notion of authentication includes not only the mechanisms needed to check identities, but also the more social problems of effective password and key management. Authorization and auditing may include various schemes of payment and chargeback, for access to services. They are also inter-related; communications privacy is a kind of authorization problem.
ILU provides two major hooks for an application to use in implementing a security policy. The first is a flexible notion of identities. The second is an interface to communications security which allows authentication, integrity, and privacy to be provided in all message traffic between two ILU-connected programs. We believe that with these two mechanisms, arbitrary security policies can be implemented with ILU.
Identities are ways in which authorization principals in a
security system are named. They can be various; human names, social
security numbers, computer login accounts, and credit cards are all
examples of identities. ILU provides a few prespecified
identity types, one of which (the GSS identity) is flexible and
user-extensible. In addition, the ilu_IdentityType
data type in the kernel
exports a meta-object protocol for defining new identity types, which can be used
by various application-specific protocols and transports.
ILU also defines a passport, which is a data structure which can contain an arbitrary number of identities. Identities are communicated during calls through an ILU interface by having the caller pass a passport as part of the call, so that the implementor of the true method can find out which principal is making the call. This passport transfer can be accomplished automatically as part of the wire-protocol used in the call, or on a per-connection basis by the transport machinery, or explicitly as a parameter of the call.
The identity types provided in ILU 2.0 are:
ilu_ConnectionIdentity
-- a string identifying the connection over which the call was made;
ilu_SunRPCAuthUnixIdentity
-- a data structure (see `runtime/kernel/iluxport.h' for details) identifying the (unauthenticated) user ID, group ID, and UNIX group memberships on the (putative) calling machine (this identity type is only available if ILU has been configured with support for the sunrpc
protocol);
ilu_GSSIdentity
-- an opaque value which identifies the caller via one or more GSS security mechanisms (this identity type is only available if support for the security
transport layer has been configured into ILU).
Passports, and the identities in them, are represented in different ways in different language-specific runtimes. This section contains only a brief description of the various identity types; refer to the ILU documentation for your programming language to see how passports and identities are manipulated in that language.
The `connection' identity can be used to display the apparent IP host address of the caller; due to the possibility of IP packet spoofing in IPv4, that address should not be relied upon for security purposes. Another problem with using connection identities in server applications is that ILU will close them and re-constitute them at need, which means that a client might in the extreme case use a different connection for every call. This renders the connection identity somewhat inappropriate for identifying particular client-server `sessions'.
The `Sun RPC Unix Authentication' identity follows the `system authentication' scheme described in Internet RFC 1831. It contains the host IP address, the UNIX user ID, and the UNIX group ID of the caller, and a list of the UNIX groups to which the caller belongs. Note that the user ID and group ID are relative to the cller's host, not the server's host. This information is only passed if the caller is running on a UNIX machine, and if the protocol used in the connection is the sunrpc
protocol. Note that this information may be easily spoofed if the communications channel is insecure.
The `GSS' identity may contain multiple different identities, in the form of GSS `names'. GSS naming is flexible and extensible, so should be able to represent any type of name desired. These identities may be reliable, even in the face of insecure networks, if they have been negotiated and communicated with an appropriately secure GSS security mechanism. Any effective security mechanism for use with ILU should use some form of GSS identity. ILU provides ways to retrieve parameters of the GSS identity, including the gss_name_t
of the caller, the lifetime of the security context, and the security mechanism that has validated the identity and protected the communications. There are also routines to convert a gss_name_t
value to a printable string, and to create a GSS identity given a value of type gss_cred_id_t
. Further information on the GSS can be found in the ILU distribution, in the directory `ILUSRC/GSS/doc/'.
ILU provides for transparent communication between ILU address spaces when an operation is invoked on a foreign (supported outside the calling address space) object reference. There is a generic scheme for securing inter-address-space communication, using the IETF Common Authentication Technology working group's Generic Security Service (GSS) API. (The ILU distribution also provides an implementation of the GSS, which contains a meta-object protocol allowing specific security mechanisms to be registered with and used by the GSS shell implementation.) Inside the generic mechanism, specific security mechanisms can be selected to give various degrees of protection. The GSS-based inter-address-space security provides message integrity and/or message privacy services, depending on which specific services are requested of the specific security mechanism selected for use. All parts of the message are protected; all messages on a secured transport are sent as record-marked GSS tokens. Multiple tokens may be sent for a single RPC-level message; some security mechanisms may insert empty padding messages to further confuse traffic analysis attacks. This inter-address-space security may also be used for ILU `transport-buffer-based' object persistence mechanisms, but it is not clear to us what security implications this has.
ILU communications security is orthogonal to the choice of RPC protocol or transport mechanism. The ILU transport stack consists of the following pieces: an application layer, which calls into a caller-side stub layer, which calls into RPC-mechanism-specific marshalling code, which calls into one or more transport filters, arranged in a stack. For example, an application in C++ may call into the stubs for some specific interface, which call down into the RPC message marshalling code, which calls down to the compression transport layer (passing it either whole RPC messages or fragments thereof), which calls down to the security transport layer (which turns byte streams passed from above into security data tokens), which calls down to a simple record-marking layer (which puts 32-bit length headers on each GSS data token), which calls down to the TCP/IP transport layer (which actually writes the bytes to the TCP/IP stream). Thus, each message passed between address spaces in this example is a record-marked GSS token containing an encrypted signed compressed fragment of a full RPC message. The fragment may be a `improper' fragment -- a whole RPC message. Note that this is only one possible ILU transport stack; the layers may be arranged in other orders, within some constraints. In particular, our current design requires the security transport layer to be immediately above a GSS token record-marking layer, which in turn must be immediately above the actual transport layer (the layer which actually writes to the TCP/IP buffers, for instance). The GSS token record-marking layer may adapt to the particular security scheme being used; in particular, if the wire format of the security mechanism already specifies record-marking information, the record-marking layer will simply interpret that information, rather than adding any new information to the packets passing through it.
ILU objects are managed by kernel servers. There may be multiple kernel servers per address space. Each kernel server `owns' some set of ILU object instances, and manages certain functionality for those instances. One item of functionality managed by an kernel server is communication with kernel servers in other address spaces. This inter-kernel-server communication is always performed between a `true' kernel server, or TKS, and its counterpart in another address space, the `surrogate' kernel server, or SKS. Instances in a TKS are those which actually contain implementations for the operations of the instances' types, so the TKS may be thought of as the `server-side' kernel server. A SKS manages surrogate or proxy instances for some subset of the instances managed by its corresponding TKS, so the SKS may be thought of as the `client-side' kernel server. There may be many SKSs corresponding to any single TKS, but there may only be one SKS for each TKS in any one address space. All inter-address-space communication is between a SKS and its corresponding TKS.
Selection of security mechanisms for access to instance operations is done by calls to the ILU kernel on the server side which create `ports' on true kernel servers. Each port describes a particular communication mechanism which SKS's may use in communicating with the TKS. Each port may independently select an RPC protocol and transport stack, and (if the transport stack includes the security transport layer) identify which security mechanism to use, and which server-side identity to use in establishing security contexts via that security mechanism. Communication with that TKS by any of its corresponding SKS's may then be accomplished through any of the ports on the TKS. In the call to create a port, the server-side application code passes a passport containing an ILU GSS identity, which is used as the identity of the principal offering the service, and put into the connection information in the string binding handle of objects on that server.
When a client decides to use a particular object, it consults the string binding handle of
the object to discover communication parameters for that object,
including the parameters of the various ports of the TKS for the object.
The client then creates a SKS for the TKS, if one does not already exist
in its address space, and indicates which types of communication channels it
wishes to use. A communication channel is an abstraction which
incorporates the notions of RPC protocol (say, the OMG IIOP
, though others are
possible with ILU), message transport (say, TCP/IP), and possible message transformations
such as compression or security.
Note that TKS's can force a particular communication channel type by
either only opening one port, or only telling this particular client
about one of its ports.
When a client opens a communications channel of a particular type, the
SKS initialization code automatically creates the proper RPC protocol
object and transport layer stack on the client side, initializing each
layer in the transport stack as appropriate. If the transport stack
includes the security transport layer, it also initializes this layer.
The security transport layer is written against the GSS C API, using no
extensions. The initialization code retrieves the client's identity
(from the passport of the client), the server's identity (one
of the parameters of the port, and passed as a parameter to the secure
transport layer's initialization code), and the specific security
mechanism to use (specified as a string, which may be either the
GSS-specified string form of the security mechanism OID, or an ILU
nickname for it (an optional feature)). The init code then calls
gss_init_sec_context()
with the client
credentials, the server identity, and the security mechanism. Any
context token output by that call is passed through the lower-level
transport layers to the TKS, where it is passed to
gss_accept_sec_context()
. Any return token is passed back, etc, until
the security context is established. This sequence of messages is
called the security context handshake.
Note that at this time, and in all future uses of the channel, the actual transport mechanism, TCP/IP, is used only to convey GSS tokens back and forth, typically with some simple record-marking protocol which may either be provided by the particular wire format of the security mechanism (if any), or via an additional optional record marking layer between the security layer and the TCP/IP layer. No recognizable RPC messages are ever sent on the TCP/IP connection.
After the client has opened a channel to the TKS, calls may be made
on objects in that TKS. When a call is made, the client calls down into the marshalling stubs
with an indication of which channel is to be used for the call. If no
port is specified, the SKS makes the choice according to simple
defaulting rules. Typically, a SKS has only one channel open to its
TKS, and the client accepts it by default. The marshalling stubs build
up the appropriate RPC message, and dispatch it, either whole or in
fragments, to the top layer of the transport stack. For the purpose of
this discussion we'll use the term fragment, but it is important to
remember that a whole message is also a valid `fragment'. Each layer of
the transport stack transforms the fragment in some way, and passes it to the next lower layer. In
particular, the security transport layer takes the fragment and applies
gss_wrap()
to it, using the security context that was negotiated when
the channel was set up. The wrap procedure may perform either message
integrity on the fragment, or message privacy, or both. This produces a
GSS data token, which is passed to the next lowest layer for possible
additional transformation and eventual transport to the TKS. On the
true side, the stack is reversed; a GSS data token coming in is passed
to gss_unwrap()
, which either verifies the message integrity check, or decrypts the token to
produce a fragment, or both, and sends it up to the next highest level.
To use GSS security in an ILU application, either client or server, your ILU installation configuration must have included the secure transport filter. You will also need an implementation of the GSS, with the C API specified in the (now obsolete, but not yet superseded) internet draft `draft-ietf-cat-gssv2-cbind-01.txt'. The ILU distribution comes with such an implementation, in the directory `ILUSRC/GSS/', and will build and use this implementation unless another is explicitly specified at configuration time.
To export an object via a secure connection, the true module will need to (1) establish an identity via
some GSS scheme, and (2) create a true kernel server with a port that uses the secure transport filter in its tinfo
stack. In this discussion, we'll use the ANSI C mappings and funtions.
To establish an identity, the true module must first acquire GSS credentials for some identity + security-mechanism pair; see the documentation on the GSS in `ILUSRC/GSS/doc/' to see how to do this, or take a look at the code in `ILUSRC/examples/test1/srvr.c'. Then the module will create an ILU
GSS identity, by calling the C API function
. This identity must be placed in an ILU passport, by calling either of the functions ILU_C_AcquireGSSIdentity
or ILU_C_CreatePassport
. The server module then creates a TKS by calling ILU_C_AddIdentity
, passing in as parameters a transport info list which includes the secure transport filter, and the passport. A suitable transport info list should contain a record-marking layer immediately below the secure transport filter, and may need another record-marking layer above the secure transport filter, depending on the RPC protocol being used. For example, if the protocol being used is ILU_C_InitializeServer
sunrpc
, an appropriate transport info list would be { "sunrpcrm", "security_1_Xerox.ILU.GSS.NIL", "sunrpcrm", "tcp_0_0" }
. For the CORBA IIOP
, which does not need a record-marking layer below it, a suitable layering would be { "security_1_Xerox.ILU.GSS.NIL", "sunrpcrm", "tcp_0_0" }
.
You will note that there are two parameters in the transport info string for the secure transport filter, "1"
and "Xerox.ILU.GSS.NIL"
. The first is the ILU version number of the secure transport filter; the second identifies the security mechanism being used `behind' the GSS shell. This security mechanism identifier is typically specified as a dotted-decimal representation for the ISO OID for that security mechanism. For example, to specify the Kerberos 5 security mechanism, you would use the string "1.3.5.1.5.2"
, which is the assigned OID for the Kerberos 5 security mechanism. The secure transport filter can recognize a small number of nicknames for security mechanisms (currently just "Xerox.ILU.GSS.NIL"
and "Xerox.ILU.GSS.SSL"
). You should consult your GSS implementation to see what specific security mechanisms are supported, and what the ISO OIDs for them are.
When the client makes a call on an object exported via a secure channel, the client may have to provide an identity of its own, if the security mechanism selected by the true module requires one. To do this, the client performs the same steps the true module went through: calling the GSS to acquire credentials, and then calling the ILU kernel to create a passport containing a GSS identity. The client passes the passport in a language specific way, when making the call. For the ILU C bindings, the client should bind the callerPassport
field of the environment passed in to the call to an appropriate passport, before making the call. If the object has been exported via a secure port, the first call on the object will result in the client address space negotiating a secure channel to the server address space, using the identities passed in by the client, and provided at port creation time by the server. Subsequent calls on that object will use the same security context and identities.
In the true method code for an object exported via a secure channel, the GSS identity of the caller will be available in the callerPassport
field of the ILU_C_ENVIRONMENT
parameter for the call; in C, use the
function to obtain it, and the ILU_C_FindIdentity
function to display it. (Note that the ILU_C_DecodeGSSIdentity
function is provided as a convenience.) The true method can use this identity to do authorization, accounting, and other application-specific security functions. If the security mechanism doesn't require an identity from the caller, the special GSS identity of ILU_C_GSSNameToString
anonymous
("2.16.840.1.113687.1.2.1:<* anonymous *>"
) will be passed as the GSS identity for the caller.
Go to the previous, next section.