Legion's security model has two layers, shown in Figure 4. The message layer is responsible for ensuring that communications between Legion objects are secure. The MayI layer is responsible for access control, and it determines what objects (or users) are allowed to call a particular object's methods. It also relies on the message layer for some services, such as encrypting rights certificates.
The message layer intercepts every message that is sent from or received by an object. For outgoing messages, the layer uses the implicit parameters associated with the message to determine what security measures to apply. Implicit parameters here are similar to Unix environment variables, although their values are not restricted to strings.
An outgoing message can be sent in three ways: in the clear, in protected mode, or in private mode. When a message is sent in the clear no encryption or other security processing is applied to the body of the message. An eavesdropper can extract any information from the message, and if certificates are included (explained below) it can use them in constructing fraudulent methods calls.
In protected mode, the body of the message is not encrypted. However, any certificates sent with the message are encrypted, as are the tags uniquely identifying the method call with which this message is associated. The body of the message is cryptographically digested. These transformations yield several guarantees. First, the certificates cannot be extracted and used by an attacker in another message. Second, the attacker cannot modify the message in any way, although he can copy it and replay it. Finally, the attacker cannot forge a reply message (e.g., the return value for a Legion method call) because he cannot access the tags.
Private mode encrypts the entire message. Full encryption provides the same features as protected mode as well as privacy (in protected mode, an attacker can still read the messages going by, even if he can't modify or forge them). For small messages full encryption is not appreciably slower than protected mode and may even be faster.
The choice of message security mode is stored in the current implicit parameters. These parameters are inherited through call chains, so if one object calls another object in private mode, the called object will use private mode for any messages it sends on behalf of the original caller. There is also a special implicit parameter for message security that is not inherited; it can be used to send an encrypted message and receive an unencrypted reply.
The basis for all of these security mechanisms is public key encryption. When an object's LOID is created, typically by a class object, it is given a newly generated public key pair. The public part of the key becomes part of the object's LOID, and it can be used by others to encrypt their communications to that object or to verify that received messages were actually generated by the object. The private key of the object is never revealed. The object's class, host, and vault all could potentially access it, although in the University of Virginia (UVa) Legion implementation they do not. In Legion an object implicitly trusts its class, host, and vault.
Because public key encryption is expensive, caching is used so that objects engaged in repeated communications can reuse a DES session key. These cached keys eventually time out (after thirty minutes in the current release) and are refreshed.
Though the message layer can protect individual messages, it cannot stop an attacker from simply calling the methods of an object. The MayI layer fills this role.
When an object that has a MayI layer is called, MayI examines the method call before the method is actually invoked. (The name of MayI comes from the idea that the caller is asking "May I call this method?") If the call passes the access control policy being enforced by MayI, it is allowed. Otherwise, a security exception is returned to the caller.
Legion objects are automatically built with MayI, although you can turn off or alter the default MayI or write a new one. Note that if you do not enable the security features when you first start your system (see "Choose your security setting") the default MayI will be turned off.
If an object with MayI is created but has no special access-control information in its implicit parameters, it will be "fail safe": It will only accept calls from itself or its class. Of course, the object's first action when it begins running might be to modify its access control policy. Normally, however, the creator of the object will pass an access control policy in the initial implicit parameters.
The UVa MayI is very flexible and supports many access policies. The MayI for an object can maintain separate access control information for each method as well as a catch-all that applies to any method not otherwise listed. The access control information records who is granted the right to call a method, who is explicitly denied this right, and who may generate a certificate for the method.
The "deny" list exists because groups may be specified in the access control lists. Adding the name of a context to the "allow" list, for example, permits every object whose LOID is stored in that context to call that method. However, if the "deny" list for that method contains the caller's name or a context containing his name, the call will be denied. Because resolving groups is somewhat time consuming, MayI caches the results of its lookups. This means a user added to a group will not be able to access an object until the object's cache entry for that group expires. The default expiration time is five minutes.
Certificates are another means of granting and obtaining access to an object. A certificate consists of a list of methods, an optional timeout, and an optional class LOID that restricts the certificate to instances of a particular class. It is cryptographically signed by a particular object. Any object may be given a certificate.
If an object presents a certificate to another object's MayI (i.e., includes the certificate in the implicit parameters of the method call), MayI will check that the certificate is properly signed, that the method being called is named in the certificate, and that the maker of the certificate has the right to grant access to that method. This last information is checked in the per-method lists maintained by MayI. MayI also checks the timeout and class information in the certificate.
Certificates form the base for the concept of users in Legion. A Legion user is represented by an AuthenticationObject, which supports a "log in" method. The legion_login utility can be used to obtain a password from an unknown person and then send it to a specified AuthenticationObject for verification. If the password matches, the AuthenticationObject creates a certificate and sends it back to legion_login, where it is placed in the implicit parameters. All utilities run during the session will inherit these implicit parameters and thus the certificate, and they can then be used to do work on the AuthenticationObject's (and therefore the user's) behalf.
Because Legion is a distributed system, some familiar concepts of traditional monolithic system security are different. For example, there is no central password file: each user's password is stored in the corresponding AuthenticationObject. Furthermore, any user can create an AuthenticationObject and create objects that no one else can call. There is still some control, though. For example, the system administrator may be the owner of an object that provides a resource such as printing. If that object looks in a particular group to determine access, and the system administrator has not added a user to that group, access will be denied.
We should note that Release 1.6 of the system has not been hardened to withstand attack. For example, by sending an appropriately mangled message, a sender can crash an object because the low-level message processing layers will not understand the headers. These changes are currently in progress.
Legion 1.6 includes the necessary support to operate in environments that require Kerberos authentication. The guiding design principle of this Kerberos support is that no process should be created by Legion without Legion first presenting to the underlying operating system valid Kerberos credentials for the target user.
There are two fundamental components of Legion's Kerberos support. First, each Legion user creates a Kerberos proxy object and uploads her valid Kerberos credentials into her proxy object. Second, the target machine's host object explicitly contacts the target user's Kerberos proxy object whenever a process must be created on that machine for the target user; the host object then uses the Kerberos credentials stored in the user's Kerberos proxy object when performing a Kerberos ksu command in order to create the process. Of course, Kerberos credentials are encrypted for transmission from the Kerberos proxy object to the target host object (i.e., they do not travel across the network in the clear).
Legion's Kerberos support is not currently fully documented; a small collection of sites that use Kerberos are working with the Legion developers to define and improve Kerberos support in Legion. In the near future, we will include detailed information regarding the creation and use of the Kerberos proxy objects from both the user perspective and the system administration perspective. If you currently require Kerberos support in Legion, send email to <firstname.lastname@example.org>.