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 ClassObject, 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.
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 not automatically built with MayI. The MayI object file must be linked into an object during the compilation phase. A Legion user can easily implement her own MayI by modifying the one distributed with Legion or by writing a new one.
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 password is stored in the corresponding user's 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.2 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.