• Ingen resultater fundet

Figure 5.4: Port number generation

5.2 The RPC interface

In section 2.4.3 we described the API to the RPC library. This section will describe how it will be changed in our implementation. Since we are only de-signing a prototype, only the functions used by RPCgen (the ones referred to as the lowest layer in section2.4.3) is changed. We have tried to keep the in-terface from the original RPC library, so the code the RPC programmer has to create will resemble the code used in the original RPC. Our prototype will only support UDP so we will concentrate on the interface functions associated with UDP.

On the server side we have added one function and removed the function which was used to remove previous mappings of the service from the portmapper tables, pmap_unset.

svcudp_create Since our design will assign port numbers to each role, dy-namically, it will no longer be possible to specify a socket, instead the function will always create a socket, calculate the port number on which the service is available for the given role, and bind the socket to this port number. To calculate the port number the functions need to know the descriptive string belonging to the users current role and the public key, this means that the RPC programmer must generate the descriptive string and pass it to svcudp_create as a parameter. Besides the port number svcudp_create needs a role number and the private key for this role to create the transport handle, these are also given as parameters. Because each role must connect on its own port number, it will be necessary to create a transport handle for each role, so svcudp_create must be called for each role.

pmap_unset This function is no longer needed since we do not use the portmap-per.

get_role_name This function can be used to read a role name from a le.

It is only meant as a help to the RPC programmer if he wishes to use the role name to create the descriptive string used to generate the port

number. It will take the role number and le name as parameters and return the name associated with the given number.

svc_register The primary purpose of this function was to register the service with the portmapper, but this is no longer needed. Instead this function will be used to specify which procedures each role has access to, so it must be called for each role, and the RPC programmer must specify which procedures the role has access to and pass these as a parameter. Since we register each role instead of each program version, we need to pass the role number instead of the program and version number.

The most signicant changes to the original interface functions used by the server, lie in the change that we need to create a transport handle for each role, instead of only creating one for each service, and that the RPC programmer needs to generate the descriptive strings and the keys, and specify the procedures each role has access to.

The only change in the client side interface is introduced because the port number must be generated instead of obtaining it by querying the portmapper.

clntudp_create It will no longer be possible to specify the port number in the socket data structure, since clntudp_create will always generate the port number from the public key and descriptive string and set the port number. It is no longer necessary to pass the program and version number as parameters, because we will not use these to query the portmapper, instead the descriptive string and the public key is sent along. The same changes will be made to clnttcp_create.

clntudp_call The parameters for this function will remain the same as in the original rpc. clntudp_call will still be responsible for sending the request and receiving the reply. Besides this it will also take care of the encryption and decryption. Also it will be changed so the request messages will be structured as described in section 5.1.

clnt_destroy No alterations will be made to this function.

The client side interface is almost the same as in the original. The only dierence is that the RPC programmer needs to generate the descriptive string and pass this to clntudp_create instead of the program and version number. Besides creating the arguments for the functions mentioned above and calling them, the RPC programmer must create the dispatch function, which is responsible for decoding the arguments for the procedure, calling the right procedure, and calling the function which will send a reply to the client. The dispatch function uses the procedure number to call the right procedure. This means that each dispatch function must not control more than one version, because this could lead to one dispatch function which controls two procedures with the same number.

The RPC programmer can also create a series of services, which have the same roles and read the keys from the same les, thereby making the key dis-tribution easier. However. he must be aware that two roles with the same key must not have the same descriptive string, since this will lead to hash collision.

The system administrator is also able to associate dierent roles with the same key, by storing the same key in the les used by the roles he wishes to associate.

5.3. RPCgen 45

5.3 RPCgen

Here we will describe the features we wish to add to RPCgen and the changes that are necessary in order to make RPCgen able to parse the new keywords, we will add to RPC IDL, and generate code which will use the new syntactic constructs in the RPC library1. We need to change the existing calls into the RPC library to call our extended versions of the interface functions instead, and add some new features to RPCgen. Original implementations of RPCgen can create a server and client stub, lters to serialize data, and a header le. Besides this more recent implementations can generate sample code, which shows how to interface with the client and server stubs. These can be used as a starting point for the RPC programmer.

Our version of RPCgen should be able to generate keys to be used in our access control. We will use a cryptographic library to generate a public/private key pair, which is stored in two les; one for each key. This needs to be done for each role dened in the RPC IDL program denition le. The public keys will then be distributed to the users, so that each user receives the keys associated with the roles of which he is a member. The private keys are given only to the server. To give the system administrator the possibility to replace the keys used by a role, we will add a ag to RPCgen, which will cause only the keyles to be created, these can then be distributed to the clients who will replace the original les.

As described in section 4.2.2 RPCgen will generate port numbers based on the method used in Freenet to generate keys. To ensure that it is not possible to calculate the port number from the public key alone, the descriptive string must be calculated on a shared secret between the server and the members of a role. Besides this the system administrator need some way to change this secret if it is compromised, and to ensure that old members of a role does not know the secret. We have chosen to use the role name as a shared secret, and this should be read from a le or given as a parameter, so it is possible to change it.

The string will also include the program and version name and number. These together with the role name and number ensures that the string is unique for each role. To change port number at a regular basis we also include the current date in the string, so it will change every 24th hour. Thus ending up with a string on the form:

<hostname >/Program_<Program number >_Version_<Version number >/

<Program Name >/<Version name >/<Role name >/<Role number >/<Date >

To allow the system administrator to change the shared secret used to create the strings, our version of RPCgen will create a le, which will map role numbers into role names. This means that whenever a new port number is generated the role name associated with the role, which is about to be assigned a new port number, is found in this le. Since this le will be written in clear text, the administrator can either choose to change the le in an editor or use RPCgen to create a new le, but then he needs to change the RPC IDL program denition le instead. Whenever a role changes name the administrator must distribute this to the members of the particular role, but as with key distribution the system to distribute this is beyond the scope of this project.

The changes to the RPC library means that both the generated server and client code needs to be changed. For the server we will need to create multiple

1These are described in section 5.2

transport handles for each version instead of using the same for all procedures.

svcudp_create must be called for each role in each version. Before each call to svcudp_create we must generate the descriptive string, according to the algorithm described in section 5.1.1, and the name of the les in which the roles public key is stored. For the call to svc_register we must specify the procedures the role has access to.

In order to enable the RPC programmer to specify role access assignment, we have chosen to extend the RPC IDL with a keyword specifying the relationship between a key and the set of procedures to which it grants access. For each version of each program dened, it is possible to dene a list of roles, i.e. each role denes a set of procedures in the program, which are accessible using the key associated with the role. To illustrate this, we give an example of a simple RPC IDL denition using the extended syntax:

program PRINT_PRG {

In each role, the list in brackets indicates the set of procedures to which the role is granted access. Each role is declared with a role name and number, which are used internally in the same manner as program and version numbers in the original RPC protocol. The full syntax of the extended IDL is given in appendix A.

5.4 Summary

We have described how we will incorporate access control into RPC. Each service will be divided into roles, where each role will have access to a subset of the procedures provided by the service. Each role will have a port associated, where requests from members of this role are accepted. To ensure that only requests from the members are accepted, the roles each have a public/private key pair, and all requests must be encrypted with the public key. The server can then verify role membership by decrypting the request with the private key. Role membership is obtained by possesion of the public key associated with the role, and knowledge of the shared secret between the server and the role. The shared secret is used in our naming scheme, where we generate port numbers from a descriptive string and the roles public key. This is done to enable clients to identify on which port they are able to communicate with a service.

Integrity and condentiality is ensured by applying hash values to each mes-sage and encrypting them. As mentioned the cryptographic access control is done with an asymmetric cipher and the messages are encrypted with a sym-metric key.

5.4. Summary 47 We have also described how we will change the RPC API, and how RPCgen will be changed to make use of the changes and new features added to RPC.

Chapter 6

Implementation

We will now describe the implementation of our prototype of Remote Procedure Call with Cryptographic Access Control (CACRPC). The implementation is based on Sun Microsystems' version 4.0, the source of which can be obtained from ftp://playground.sun.com/pub/rpc/. This rather outdated version of RPC was preferable to the one that ships with a modern Linux distribution, since the latter is integrated with the GNU C library. This makes it dicult to introduce changes without aecting some other part of this very complex system.

The Sun implementation, which is from 1989, rst had to be upgraded to comply with modern C standards, and any references to old system calls had to be removed. This process has not been entirely completed, so some warnings due to uses of deprecated functions may occur at compile time. The age of the code also means that some features are lacking, especially the Secure RPC authentication avor implementation has been left out due to the export restric-tions on the DES algorithm enforced by the U.S. government at the time. This is not a problem, however, as this part of the RPC standard is not important for our purposes. We have also backported some improvements made to the implementation of RPCgen in GLIBC to the old Sun version. These include the sample code and makele generator components.

6.1 Choice of Cryptographic Algorithms

There exist a great selection of dierent cryptographic libraries that implement the most popular algorithms and nding the one best suited for a particular application is not a trivial task. We have chosen to base our prototype on the Nettle library by Niels Möller [17]. It has the advantages of being very low-level, in that it does not do automatical algorithm selection, memory management, and so on. This means we can apply encryption directly on the data in the XDR data buers used by the existing RPC implementation. Nettle is also relatively simple to use, and has support for the needed functionality.

We have chosen the AES algorithm for symmetric encryption, since it is a well-proven algorithm with support for the key sizes required in modern systems.

All encryption is carried out in CBC mode, in order to prevent block manipula-tion. Asymmetric encryption is done using the RSA algorithm. This is in fact

49

the only asymmetric algorithm supported by Nettle at present, but this is not really a problem, as it is an old algorithm that has withstood cryptanalysis for almost thirty years. One downside is that it requires fairly large keys in order to be considered secure. Since no security system is stronger than its weakest part, the most ecient use of resources is obtained if all the used components are approximately equally dicult to attack through brute force. RSA security claims that 2048 bit RSA keys are equivalent to 112 bit symmetric keys, and considers data encrypted with such a key to be secure until the year 2030. Since the minimum key size of AES is 128 bits, we cannot obtain perfect equivalence.

This could be achieved by increasing the RSA key size to 3072 bits, if desired.

The hash function SHA-256 is used both for port number generation and for ensuring integrity. As the name suggests, it generates 256 bit hash values (since the port numbers used are 128 bits long, the hash value is truncated when used for this purpose). Due to the attack known as the birthday attack, hash values must generally be twice as long as what one immediately expects. This is due to the fact that an adversary only need to nd two random messages that hash to the same value in order to potentially be able to break a system reliant on a hash function. This is much easier than nding another message that hashes to the same value as a given message. For this reason, the hash value size of 256 bits is comparable in strength to the 128 bit keys used in AES. Being extra cautious when choosing a hash function is also very important, since a recent paper by Chinese cryptographers Xiaoyun Wang, Yiqun Lisa Yin, and Hongbo Yu, reveals a weakness in one of the most popular hash functions, SHA-1, making it 2000 times faster than brute force to nd a collision. SHA-256 might be vulnerable to similar attacks, but with its much larger hash value length, it should be secure for the foreseeable future even if such problems do exist. An attacker nding a collision is primarily a problem if he can use it to compromise message integrity.

Finding colliding port numbers is not really a security risk.