TD.1.2-D Implementation of Security in the IPF
Marcus Roberts
Queen Mary and Westfield College

 

Contents

Section 1, Introduction summarises the intended purpose of this document.

Section 2, The relationship between secure communication and authentication describes why the implementation has separated the protection of data and authentication of principals, even though both use related cryptographic techniques.

Section 3, Secure Communications, describes the implementation of the secure communications module and the cryptographic protocols used to negotiate session keys to protect the privacy and integrity of data transmitted between PDs.

Section 4, Authentication, describes the implementation of the authentication component, discussing the problems introduced by migration, and the protocol used to minimise public-key based signing of data.

Section 5, Access Control, describes the component that receives and evaluates requests for access to resources. It discusses how the evaluations are made, and how the information needed to evaluate the requests is stored. It also describes the protocols necessary to maintain the integrity of the access control information in a distributed environment with non-uniform trust.

1. Introduction

The PerDiS deliverable document TD.1.1A [TD11A] proposed a set of security design goals for PerDiS and gave a rationale for them, and proposed a trust model for a virtual enterprise. PerDiS deliverable TD1.2.A [TD12A] proposed a design for the implementation of the security design goals derived. This document describes an implementation of the security architecture integrated into the IPF release of the PerDiS platform.

 

The security architecture can be decomposed into three main components - Secure Communication, Authentication and Access Control. Each component is considered separately, but the interactions between the components are discussed where appropriate.

The secure communications component is concerned with maintaining integrity and privacy of communication between PerDiS Daemons (PDs). This is achieved through the use of cryptographic protocols to provide digital signatures to validate the integrity of messages, and encryption to protect the contents of a message.

The authentication component provides for local and remote validation of the identification claimed by principals. The mechanism is based on a "lazy" protocol that promotes maximum use of shared keys and the minimal use of public keys to authenticate an identity. The protocol tackles the problem of "fragmentation" and migration of clusters between many PDs.

The access control component evaluates requests for access to resources and maintains the information needed for evaluating these requests.

This document describes the security implementation at the level of the protocols used and the modules that implement them. For a more technical discussion of the implementation see the implementation documentation in appendix A and appendix B.

 

2. The relationship between Secure Communication and Authentication

The initial design described in TD1.2.A envisaged a close coupling between the secure communications component and the authentication component, as the encryption used to protect messages passed between PDs could also be used to authenticate the originator of the message.

This would result in a scenario as shown in the figure above, where a separate key is used for each pair of principals. The negotiation of the session key for the channel would involve the authentication of the principals at each end of the channel. Hence, any future messages received over the channel protected by the session key would implicitly authenticate the sender and receiver. The secure communications component would hence protect the data, and also signal authenticity to the other components.

However, in the current implementation described in this document, the secure communication and the authentication are two discrete components, each employing their own specific protocols.

The secure communications component establishes a single communication channel between a pair of PDs, and protects it using a single session key, negotiated on the authenticated identities of the PDs being connected. All data between the two PDs flows over this single channel, and no authentication information is passed to other components.

The authentication component negotiates a session key between each pair of communicating principals. This key is not used to protect communication between the principals, but is used only to authenticate their identity to each other.

There are two reasons for this. Firstly, separating the secure communication from the authentication allows for strong authentication even when secure communication is not being used. This may be important, as at the present time the legal status of the use of cryptography for protecting communications is under debate, and strong distinctions are being made between cryptography used for privacy, and cryptography used for authentication. By having separate keys and mechanisms, authentication can continue to be provided even if the secure communication module is not present. Also, if different strengths of cryptography are allowed for different applications, a separation is again useful.

Secondly, separating authentication and secure communication has drastically simplified the design and implementation of the secure communication component. The non-secured implementation of the communications module sent all traffic between a pair of PDs over a single channel. Securing this single channel through the use of a single session key was a simple task. Because the authentication of higher level principals is based on their public-private key pair, it would have been necessary to have each message originated by a principal encrypted with that principal's private key (or an associated session key). This would have meant multiplexing messages signed with different keys over the same channel, or the establishment of a channel per high-level principal pair.

The requirements for each component are sufficiently different that separation has been useful, and its side effects beneficial in the main. The only concern is a duplication of effort, and this is discussed in detail in the appropriate sections.

 

3. Secure Communications

Introduction

The secure communications component is concerned with providing private and tamper-free communications channels between PDs across local and wide-area networks. This is accomplished through the use of well-known cryptographic techniques. The level of protection can be tailored according to the level of trust between communicating PDs, and the perceived hostility of the intervening network.

In essence, a shared secret encryption key is used to protect the communication. The data sent over a communication channel can be encrypted using the key to avoid eavesdropping, the contents can be signed to avoid tampering, and nonces can be used to avoid replay attacks. In practice, any combination of the three may be used, depending on the perceived threat, and sensitivity of data.

In the PerDiS security model, PDs in the same trust domain will have a shared domain secret key that can be used for securing communication. When PDs are in different trust domains, their public keys are used to negotiate a shared key at the start of communication.

The secure communications component allows a mixture of data to be sent as signed, encrypted or in the clear over the same channel. This is in contrast to the Secure Sockets Layer (SSL) protocol, which requires a common approach for all data over the same channel. In the design process, it was envisaged that a mixture of sensitive and non-sensitive traffic would pass over the same channel, and that it would be inefficient to encrypt data that did not require it. For this reason, as well as for other reasons of efficiency, a proprietary secure communications module was coded. The re-use of a large number of SSL components made this a relatively simple task. SSL itself could have been used to achieve the same result (but without the flexibility of mixed traffic).

Implementation

Each PD has a public-private key pair, and a secret domain key for each domain it is a member of. The public key is well known and available from a public key certificate service.

When a PD first makes contact with, or is contacted by another PD, a challenge is sent, encrypted in the domain key. If the remote PD is indeed a member of the domain, it will have the domain key, and it can use this to decode the challenge, and encode the reply appropriately. Once it has been verified that both PDs can trust each other, the domain key is used for future communication.

If the remote PD is not in the same domain, a shared secret key valid for the duration of the connection must be negotiated (although a new key may be needed if the connection is maintained for longer than the life-span of the key). It should be noted that once a connection has been established between two PDs, a connection is maintained until one or both of the PDs terminate. Hence the overhead for establishing a session key is relatively small.

In the current implementation a simple key-negotiation algorithm is used. The initiator of the connection generates a random session key, and encrypts it in the public key of the PD it is attempting to establish communication with. This ensures that only that PD will be able to decrypt the key successfully. The encrypted key is then encrypted again using the originating PD's private key.

The receiving PD decodes the message received using the originating PD's public key. This allows the receiving PD to validate that the key sent came from the originating PD. It then uses its private key to decrypt the session key.

Once a shared key is available, data sent over the channel can be signed to avoid tampering, encrypted for privacy, or both. The level of protection applied is determined by the secure communications component in conjunction with the meta-information for the data being sent.

By default, if a key is available, a secure hash will accompany every message sent over the connection. This prevents tampering with the content of the message, and provides low-level authentication of messages. Authentication at the secure communication level verifies that a message was sent by the claimed originating PD. This is important for control messages that are not subsequently authenticated by the authentication component.

If the communication channel is over a potentially hostile network (typically this is defined as a connection to a PD outside of the local trust domain) then all messages will be encrypted for privacy. Each message will also have a (signed) checksum appended to it ( before possible) encryption, to allow the recipient to detect any tampering with the message content.

Finally, if the meta-information for a cluster indicates that it contains sensitive information, any message containing data from it will be sent encrypted, regardless of its path over the network.

The API for the communication module also allows a programmer writing PD modules to specify that a message should be sent signed or encrypted.

The diagram above shows a typical communication scenario. The PDs communicating within trust domain D use a shared domain key Kd for securing communication. The PDs outside of the domain use a negotiated session key only valid for communication between the pair of PDs.

 

Technical Discussion

Each pair of PDs in communication has a single socket stream connection between them. The PerDiS communications module multiplexes communication between different objects over this single connection. Each open connection between a pair of PDs is represented as a CConnection object.

When a communication server initiates a connection to a remote PD, it first establishes a socket stream. If a stream is established successfully, the originating PD will attempt to establish a session key for the connection.

If the two PDs are in the same domain, they can use the domain key as the session key for the connection. If the remote PD is identified as being in the same domain, the local PD calls pd_security::encryption_start_challenge(). The remote PD will respond to the negotiation request by calling pd_security::receive_encryption_challenge(). The local PD generates a random challenge, and encrypts it in the domain key. The encrypted challenge, along with the identity of the local PD is sent to the remote PD. The remote PD authenticates the identity of the local PD, and then decrypts the challenge with the domain key. Assuming the remote PD is indeed in the same domain, it will be able to decrypt the challenge, and then return a proper response, again encoded in the domain key. Upon receipt of a proper response at the local PD, the secure connection is established, with the domain key used as the session key.

If the two PDs are in different domains, they must negotiate a shared session key, authenticating each other's identity using their public keys. The originating PD calls pd_security::encryption_start_handshake() whilst the receiving PD calls pd_security::encryption_receive_handshake().

encryption_start_handshake() calls prepare_encryption_request() which calls the encrypt_session_key () function to generate a random session key and encrypt it in the public key of the remote PD. It then generates a request data structure containing the encrypted key and the identity of the originating PD. This structure is then signed using the originating PD's private key, and is sent to the remote PD.

encryption_receive_handshake() calls establish_peer_encryption_key() which uses the validate_encryption_request () function to verify the signature on the request structure was generated by the principal identified in the structure. If the signature is valid, the session key is decrypted using the decrypt_session_key() function. The remote PD then uses the session key to encrypt a response returned to the originating PD.

If the response is decrypted successfully at the originating PD, it knows that it is communicating with an authenticated PD, as only the PD with the corresponding private key could have successfully decrypted the session key necessary to generate the response. The remote PD knows it is communicating with an authenticated PD because of the valid signature on the request.

Once a session key has been established, the connection can be operated in one of three modes. CConnection has a set of methods: Set_to_Read_Encrypt, Set_to_Read_Authenticate, Set_to_Read_Clear, Set_to_Write_Encrypt, Set_to_Write_Authenticate, Set_to_Write_Clear. These methods are used to control the current operation of the connection. Before an object communicates over the connection, it selects the mode of operation required by calling the appropriate method. This allows each object to communicate as it requires, whilst maintaining a single connection. The three modes are
1.  clear, where no encryption is used (this is forced when certificates or keys are missing at connection establishment time)
2. authenticated, where a signed checksum accompanies each message for integrity purposes
3. encrypted, where each message is encrypted for integrity and privacy.

At the socket communication level, each time a buffer of bytes is written or read, the status of the connection, set using one of the above methods, is checked. Depending on the mode of operation, the buffer is either sent in the clear; or a checksum is generated, and either the checksum or the concatanation of the buffer and checksum is encrypted using the session key. At the receiving end, again depending on the mode of the connection, the buffer is either used as is, or the signature is removed and the contents of the buffer are verified, or the buffer is decrypted using the session key, and the checksum recalculated and compared to check message integrity. The resulting buffer is then passed to the communication server for dispatch.

 

4. Authentication

Introduction

The authentication component is charged with verifying the claimed identity of the originators of requests for access to resources. Rather than being at the level of communicating entities (i.e. PerDiS Daemons), the authentication component considers higher level principals in the application domain. These principals are mainly users assigned roles in an application task, but can also include PerDiS Daemons, as these are principals who must demonstrate their authority to grant access to a resource.

Implementation

Authentication is based on the use of a cryptographic key to provide a digital signature. If a shared key is used, only a principal who has knowledge of that key can generate a signature that can be verified as being generated with that key. If public key cryptography is used, only a principal who has knowledge of the private key can generate a signature that can be verified using the corresponding public key. Public key cryptography is significantly more expensive than shared key cryptography. For this reason, the authentication component tries to establish a shared key where possible, to reduce the number of authentications made using a public key.

An additional complication identified in the design document is data migration. Whereas in the secure communication component the identity of the entity being communicated with is known in advance, the migration of data between PDs means that the final destination of a message is not known until it arrives there.

The PerDiS cache replicates data at the granularity of the page, where a cluster is composed of many pages. The PD holding the master_lock for the page grants access to a page. If a page has not been previously accessed, by default the master_lock is held by the home site of the cluster. When access is granted to a page, a copy of the page is replicated to the requesting site. If the page is modified, the master_lock migrates to the site making the modification, and the original holder of the master_lock holds a forwarding reference to its new location.

In the example shown in the diagram, a PD requesting access to the cluster would send its request to the Home Site. Because the master_lock has migrated, the home site will forward the message to the last location of the master_lock it is aware of, i.e the intermediate site. When the request is received at the intermediate site, it too has passed the master_lock on, and so forwards the request again. Finally, at the third site, the master_lock is located, and the request can be evaluated.

The simplest way of authenticating a message would be to sign it using the originator's private key at the time of sending. The original recipient then simply has to obtain the public-key certificate for the principal to authenticate the signature. Unfortunately, this requires an expensive public-key signature to be generated for each request.

The trust between PDs within the same domain means there is no requirement for a principal-based signature on a request - it must simply be authenticated as originating from a trusted PD, and this can be done using the shared domain key. However, because of migration, we cannot tell where the request will finally be evaluated, and so we cannot decide if the request will be evaluated within the same domain as the originator or not. Related to this problem is the issue of using shared keys in general - even if there were shared keys in place that meant a public-key based signature was not required, and a cheaper shared-key signature could be generated, we would not know in advance which key holder we were going to communicate with.

The implementation of the security architecture uses the protocol described in deliverable TD.1.2.A (and in further detail in [Coulouris98] and [Dollimore98]). We always use the shared key associated with the local trust domain to sign the initial request. If the recipient (the holder of the master_lock) is within the local trust domain, the recipient will share the same domain key, and will be able to authenticate the request. The same key can be used to sign the reply sent.

If the recipient is outside of the originator's domain, the message cannot be immediately authenticated. Instead, the request is returned to the originator, along with a request to negotiate a shared authentication key. The key established is used to authenticate the original request, and any future communication between the principals involved. Usually, the principal pair will be formed from two application users, or from an application user and a PD. This is because the PD granting access to a resource must demonstrate their authority for holding the master lock for that resource. A PD obtains this authority either by being the home site for the resource, in which case the PD uses its own identity to authenticate the reply, or by having obtained the resource on behalf of a principal who has the authority to modify the resource. In the second case, the identity of the principal is used to authenticate the reply.

Once a key is established, it is retained by both parties for use in future communications. If a request is made by which requires the authentication of the same pair of principals, the key can be used again. Note that a key is necessary for each pair of principals that communicate, rather than each pair of communicating PDs, because authentication is based on application-level principals.

Technical Discussion

The access control component is responsible for invoking principal authentication before making access control considerations, and for generating security tokens for use in the authentication process at the originating PD.

When generating a request, the access control component invokes the pd_security::create_token() function. This takes a master security token, specific to the principal and the cluster, and generates a specific security token, containing information about the page and mode requested, and a signature for the request. As the token passes through the communication server, it is signed using the PD's domain key.

The access control component invokes the pd_security::verify_lock_request() function, passing it the security token received with the request. If the PD sending the request is in the same domain, the verify_trusted_request() function is invoked, otherwise verify_untrusted_request() is invoked.

verify_trusted_request() checks that the signature on the request is authentic. If it is, the request is known to have been sent from a trusted PD, and no further authentication of the principal's identity is made.

verify_untrusted_request() first checks if a shared key has been established in a previous communication with the principal making the request by calling key_store.find_session_key(). If no key is found, a negotiation is made between the two PDs to establish a shared key, using the establish_session() function, and the key is stored using key_store.add_remote_session_key().

Once a shared key is available, the PD making the request is requested to re-send the request, this time authenticated with the shared key. This negotiation is made using the in_session_check() function.

Once a request is available, signed in the shared key, the signature is authenticated, and so the identity of the requester is established.

5. Access Control

Introduction

The Access Control component has responsibility for evaluating requests made for access to resources, and granting access only to those principals who have the correct permissions. Access control involves several sub-components - RoleInTask certificates for demonstrating a principal's authority for accessing a resource, the associated public-key infrastructure for validating such certificates; storage and maintenance of the Access Control Lists protecting resources, and the evaluation of a request using these two sources of information.

Access Control Lists

Each resource protected by the PD has an associated Access Control List (ACL). The list is composed of <principal, permission> pairs. The principal specifies either a Role in a Task, or a named principal. The permission assigns the principal either Read or ReadWrite access to the resource.

For example:

Role Examiner in Task SoftwareEngineeringExam , ReadWrite

Role Secretary in Task SoftwareEngineeringExam, Read

cn=John Smith, Read

The ACL for a resource is created when the resource is created. Typically, the ACL will be derived from an ACL prototype contained in the task object for the task the resource is part of. However, the ACL may be edited at any time using the ACL editing tool (described in PerDiS deliverable TD.1.2-C [TD12C]).

The ACL for a cluster is stored in the cluster itself, as part of the meta-information of the cluster. Currently a page of the cluster is reserved for ACL information (but this is due to change under the new cluster scheme).

Accessing the ACL

As the ACL is stored inside the cluster, it is accessed in the same was as any other data stored in the cluster. This allows us to provide distributed access to the ACL information using PerDiS itself, both in the PD and for user tools.

However, an important issue is controlling access to the ACL itself. With the ACL information contained in the cluster, and access being made through the standard interface, the usual access control will be applied to such requests, and so only named principals, or principals playing roles specified in the ACL may access the ACL. There is also a need to differentiate between access to the ACL information in the cluster, and access to the remainder of the information in the cluster, particularly for write access. Finally, we must be careful to terminate the recursion involved in applying access control to the information used in making access control decisions.

As a PD trusts itself to operate correctly, it can allow itself free access to clusters and the information contained in them. When ACL information is accessed for the first time, the request for the information will (eventually) be made to the home site. When the request is received by the access control module, it must retrieve the ACL from the cluster to determine the validity of the request. It requests the ACL from the cache. Because the information is held locally, the cache can retrieve the information without further need for access control, and return it to the access control module. The module then evaluates the request. This is what occurs in PD A in the diagram below:

It is also likely that a PD will receive a request for a resource when the ACL for the resource is not held locally. In this case, before a decision can be made, the ACL must be obtained from the remote PD. The access control module requests the ACL information from the local cache, and the cache makes the request to the PD holding the ACL information. At this point, the remote access control module obtains the ACL information through its local cache. As a PD has no explicit rights to access any information, the request is made using the credentials of the principal who originated the request.

If the request for ACL information is rejected by the remote PD, we can implicitly determine that the requesting principal has no access to the cluster (as read access or greater is required to obtain the ACL information). If the ACL information is returned, then we implicitly know the requesting principal has at least Read access, and we do not need to evaluate the ACL information locally unless the principal is requesting ReadWrite access to the resource. In this case we must determine if the principal has Read or Readwrite access.

Modifying the ACL

A principal with ReadWrite access to application data stored in a cluster does not necessarily have ReadWrite access to the cluster meta-information, particularly the ACL and other security information. A second ACL specifies which principals may modify security meta-information.

This second ACL is also stored in the cluster meta-information. It is a list of principal identifiers specifying who may alter security meta-information. In the current implementation, a number of pages are reserved for information protected by this ACL. Accesses to these special pages are caught by the access control component, and if ReadWrite access is requested, the second ACL is consulted.

Clearly we need to specify who can alter the second ACL, and a third ACL is not a solution! Instead, we allow any principal in the second ACL to alter that ACL. By default, when a cluster is created, the creator of the cluster is placed in the second ACL. This allows the creator of the cluster to edit the security information of the cluster, and to assign the same responsibilities to other principals.

Securing the ACLs

Placing the ACL information inside the clusters gives us a great deal in terms of allowing distributed access to the security information. However, because the information is being obtained through distributed channels, rather than from a single trusted centralised source, there is a possibility that the information may be tampered with before being received. Tampering here is where a PD in the chain through which the information is passed may alter the information to assign rights to users who have no such rights. This may occur in order to allow the PD to claim the authority to pass the information on in the first place.

To protect against such tampering, the primary ACL is signed by the principal creating or updating it. The integrity of the ACL received may then be verified. The signature on the primary ACL must be made by one of the principals in the secondary ACL.

To protect the integrity of the second ACL it too must be signed. Without this protection, the first signature is worthless, as a tampering PD simply adds its own principal to the secondary ACL and re-signs the first ACL. We cannot use the list of principals in the secondary ACL, as this could simply be completely obliterated, and a fraudulent principal could sign themselves into the list. Instead a truly independent signature must be used - we have chosen to have the PD at the home-site of the cluster sign the secondary ACL. This means that all updates to the secondary ACL must be made through the home site PD.

 

Technical Discussion

The primary function of the access control module is the acl_test() function. The function is passed the identity of the cluster the request is being made for, and a security token generated by the requester. A security token is a generic data structure used to identify the principal making a request, and the paramters of the request.  When the token is created it is not signed, but if it is passed to another PD, a signature is applied to authenticate it.  The acl_test() function  returns the maximum level of permission the user has for that cluster.

The acl_test() function caches previous evaluations of requests for access to a cluster. Because the cluster is the unit of protection, a principal has the same level of access for any section of the cluster. Hence once a request for the cluster has been evaluated once, the result remains valid for future access to the cluster until the ACL changes or credentials are revoked or expire.

acl_test() hence checks its cache for previous results for the principal making the request by calling the find_transaction() function, and returns that result if it is found.

If no previous request has been made, the request must be evaluated. The ACL is obtained through the cache. The signature on the page is then verified by the verify_acl_signature() function, which ensures that the ACL has been signed by a principal listed in the owner list. The owner list itself must be verified by the verify_owner_list() function, which obtains the owner list using the cache, and verifies that it is signed by the home site for the cluster.

If the ACL is valid, the apply_acl_test() function is called, which evaluates the ACL and the request being made. Each entry in the ACL may specify a Role, Task and permission, or a specified principal identifier and permission. If the entry is a specified principal, and the principal matches the one making the request, the permission is noted. If the entry specifies a role and task, the credential certificates in the corresponding task object are retrieved using the open_credentials() function, and are then checked to see if the requesting principal has credentials to play the role specified in the task. Each entry in the ACL is iterated through until a ReadWrite permission for the requesting principal is found, or all have been checked. At the end of the iteration, the maximum permission found is returned.

It should be noted that this is a particularly inefficient method of ACL evaluation, as it requires multiple iterations through credential certificates, and also doesn't consider the role the principal wishes to take on. Future versions will have better search functions, and will require the user to specify the role they are claiming to play.

 

The access control component also provides functionality for the maintenance of the ACL for a cluster. The ACL itself is handled like any other data stored in the cluster. However, when the ACL is modified, a new signature must be applied to show that it was updated by an authorised principal. This signature is generated in the ULL through calling the sign_acl() function.

If the list of owners (i.e. those principals authorised to modify the ACL) needs to be altered, a request is made to the home site PD for the cluster. A principal who is already in the owner list sends a request to the PD for another specified principal to be added to the list, through the set_ownership() function. If the principal making the request is listed in the owner list, the new principal is added to the list, and the list is re-signed by the home site PD.

 

RoleInTask Certificates

The credentials of a user to play a role in a task are specified in terms of RoleInTask certificates. As discussed in the design document, it was decided to store these certificates in a task object that was itself a PerDiS object. This provides distributed access to the certificates, and also allows us to use the invalidation mechanisms of the PerDiS DSM to revoke certificates in a timely manner.

PerDiS provides a "many readers / one writer" consistency model for locks on data. Each PD making use of certificates takes a lock on the certificate data. This causes a copy of the data to be replicated at the PD. Rather than relinquishing the lock, we retain it in order to retain a consistent copy of the data locally.

Before a modification can be made to a certificate, a write lock on the data containing it must be obtained. The PerDiS cache provides for "call-backs" on data. When a request for a write lock is made on data already held in a read lock, a callback event is issued to each PD holding one or more locks on that data requesting it to release the lock. Ordinarily, this event will be used to generate up-calls to the application to see if the lock can be released. An additional handler signals the access control component that a modification is being made to the certificates it holds.

The access control component relinquishes the lock it has on the certificate data, and then obtains a new lock (and new copy) of the certificates once the modification has been made. Any access control evaluations stored in the result cache dependent on the modified or revoked certificates are flushed, and the appropriate evaluations redone when necessary.

 

Naming of users, roles and tasks

The design document TD.1.2.A discusses the naming of users, roles and tasks within the security components. Implementation of the public key certificate infrastructure, and hence the names associated with certificates and keys, has been postponed until year 3.

 

References

[Coulouris98] "Secure Communication in non-uniform trust environments", George Coulouris, Jean Dollimore, Marcus Roberts". Proceedings of ECOOP Workshop on Distributed Object Security, Brussels 1998.

[Dollimore98] "The protection of migrating objects in a virtual enterprise", Jean Dollimore, Marcus Roberts, George Coulouris, Technical Report 748, Department of Computer Science, Queen Mary and Westfield College, University of London, April 1998.

[TD11A] "Security Services Design", George Coulouris, Jean Dollimore, Marcus Roberts, PerDiS deliverable TD.1.1-A. June 1997.

[TD12A] "Security Design for the IPF", Marcus Roberts, George Coulouris, Jean Dollimore, PerDiS deliverable TD.1.2-A, June 1998.

[TD12C] "Security Tools Documentation", Marcus Roberts, PerDiS deliverable TD.1.2-C, December 1998