Parameterized Communication

Obol is a Lisp-like, domain-specific language for testing and experimenting with when constructing and using security protocols in real systems.


September 06, 2006
URL:http://www.drdobbs.com/security/parameterized-communication/security/parameterized-communication/192503712

Per teaches computer security at Bodøs Graduate School of Business, Norway, and is completing his Ph.D. at the University of Tromsø. He can be contacted at [email protected].


"Security maintainability is the elephant in the living room; people know there's an awful problem but are generally too polite to mention it (especially as we don't really know what to do with the beast)." [1]

—Ross Anderson

Security solutions are built to solve very specific cases, with very specific assumptions, parameters, and environments. Because the real world changes, security solutions gradually get out of sync with their deployment environment [2]. Sometimes the effects are undesirable, such as with key/secret leaks. There are also weird and cryptic side-effects; for example, a distributed system needs a PKI to scale, but PKIs are brittle and centralized, and do not scale [3] or, heavens forbid, you need to modify your naming scheme [4]. How do we keep up with real-world changes as efficiently as possible?

Dig around in any nontrivial security-related application, and you'll find places where it is hard to tell where the application stops and the security solution begins. The "spaghettiness" seems to worsen with the software's age, complexity, number of upgrades/patches, number of developers, and so on. There seems to be an inherent conflict of interests. On one hand, you want to maximize the flexibility of the application, add features, and whatnot; on the other, you want to have the best security available.

In a dynamic environment, this sounds brittle. Of course, there's little wonder why: A complete redesign to ensure harmony between application and security is costly. However, it's sometimes easier to redesign than to fix, which is why we get incompatible upgrades: SSH1 versus SSH2, SSL2 versus TSL, Win95 versus Win2000, and so on. For example, replacing a nontrivial security solution based on shared-key technology with one based on public-key technology is a major undertaking. If you don't think so, try modifying, say, Firefox to use password-based PGP instead of SSL/TSL—it's possible, but insanely difficult. Obol (http://www.pasta.cs.uit.no/~perm/Obol/) is a freely available security protocol programming language that has been built to address this problem.

Solution

Security protocols are a highly specialized problem domain. Consequently, general-purpose and relatively low-level tools such as Java aren't always the best match to such a problem domain and its high-level abstractions. For example, when you have to juggle knowledge properties ("A believes B said x" [5]) and authentication derivatives ("A ^ O|B speaks-for A for B" [6]), you really don't want to care about endianess, for-loop indexes, hash-tables, or string encoding. You only want to deal with the security problem at hand. For this reason, we have built the domain-specific Obol language to deal only with security protocols at a level of abstraction that is as close as possible to the theoretical tools used to analyze and describe security protocols. This lets you focus only on the relevant security issues, and allows experimentation without major redesign and reimplementation efforts. If a highly optimized integrated implementation is desirable, this can more easily be done when the resulting protocol and its interface is fully understood.

In any given protocol there are two or more participants. The protocol has a specific purpose and consists of a number of steps that must be taken by participants to fulfill this purpose. For a language dealing only with security protocols, the issues of interest are:

Obol provides eight operators and a syntactic notation to address these points:

There are other operators, called "metacommands," for controlling the Obol runtime, and dealing with input/output to protocols.

An Obol program is called a "script," and describes a participant's role in the protocol (see the sidebar "How To Program in Obol"). Scripts are interpreted by the Obol runtime, sometimes called "Lobo." Applications connect to the runtime and request that a particular script be loaded and instantiated. A script-dependent handle is then returned to the application. All subsequent interaction with the protocol is done via this handle—starting/stopping, setting and retrieving parameters, state queries, and so on. Figure 1 is an overview of the Obol runtime.

Figure 1: Obol runtime overview.

Scripts can configure the runtime to receive messages in two different modes:

An early prototype of Obol was written in Common Lisp, and this is still evident in the syntax: parens enclosed prefix statements with a variable number of arguments. Metacommands use square-brackets instead of parens. Like Lisp, symbols are named places to store data values, symbols can have any number of associated key—value properties, of which some are predefined; for example, type (which would be the type of the symbol's value, not the symbol).

Benefits

The result are (very) short protocol programs, a well-specified and flexible interaction API, and clean separation between security protocol and application. Taken together you get several benefits:

Parameterized Communication

Imagine your application connects to a server with the intent of using some service. Using Obol, the server can say, "Oh, you have to use this protocol to use that service!" The client application can then retrieve and inspect the protocol script, and if acceptable, run it.

This approach can also be turned around, so that the client says "I can only run these protocols!" The server can then examine the client's protocols, and run those that it judges to be compatible or adequate.

It might also be possible to negotiate and synthesize a script that is satisfactory to all participants, although protocol synthesis is believed to be very difficult, due to semantic consolidation over contextual borders.

Notice that even if your client application now knows which protocol to follow to access the service, use of the service itself must be dealt with by other means; for example, using Jini for driver distribution, running on top of a protocol initiated by means of Obol.

When the way communication is done has been decoupled from use of that communication, you can do all kinds of interesting things.

By embedding scripts in certificates, you gain two things:

It's possible to change a protocol while it is running. Obol can do this by copying one script's local state into another instance's state. In this case, care must be taken to ensure that the two scripts are sufficiently compatible, to make the change-over decently predictable. Exactly how to determine, mechanically, if two scripts are compatible enough turned out to be harder than we thought. We're unsure of how to make this feature safe enough to be useful, so it's disabled in all current Obol versions.

One problem is that applications that don't know about Obol can't fully participate. Obol has been constructed so that message representation during transport has no side-effects in the language proper, meaning that it's nice if both sides utilize Obol, but it's not required. As long as the Obol environment can parse and represent messages in a way that's understood by the peer, the protocol can progress, although the Obol side is limited to striving for compatibility with the peer. Unfortunately, although the message representation machinery is modular, representation formats cannot yet be encoded in the Obol language, but must be provided as Java classes.

There is also another problem, which Obol shares with middleware in general—what to do after all the reflection and inspection has been done. It's possible to enter the state where the protocol has been negotiated and executed successfully, but the application has no clue what to do with the result.

Reflection/Inspection

Before a protocol can be executed, it must be examined to learn what input it needs (keys, names, IP addresses), and which results it yields (if any).

Obol scripts use the metacommands [input] and [returns] to specify their input requirements and return values. All input requirements must be satisfied before execution proceeds. Applications can access the set of unset input requirements, and the set of script-set return values at any time. There is a simple event-notification mechanism allowing applications to be notified (or they can poll) of state changes, such as a new input requirement, results becoming available, or that an error has occurred. Listings One and Two show how this mechanism is used by client and server applications, respectively.

import lang.API;
import lang.Runtime;
import lang.ScriptHandle;
import lang.ReturnValue;
import lang.ObolException;
 ...
API lobo = Runtime.getInstance();
ScriptHandle script = lobo.getScriptInstance(lobo.loadScript("./server.obol"));
script.setSymbol("portNo", 1234);
script.startExecution();
try {
   while(true) {
      int status = script.waitForStatus(ScriptHandle.STATUS_DONE);
      if (0 != (status & ScriptHandle.STATUS_RESULT_AVAILABLE)) {
         System.out.println("Received \"" + 
           script.getSymbol("data").getValue() + "\"");
      }
      if (0 != (status & ScriptHandle.STATUS_DONE) {
         break;
      }
   }
} catch (ObolException e) {
   System.err.println(e);
}
Listing One
import lang.API;
import lang.Runtime;
import lang.ScriptHandle;
import lang.ObolException;
 ...
API lobo = Runtime.getInstance();
ScriptHandle script = lobo.getScriptInstance(
lobo.loadScript("./client.obol"));
script.setSymbol("portNo", 1234);
script.startExecution();
try {
   while(true) {
      int status = script.waitForStatus(ScriptHandle.STATUS_DONE);
      if (0 != (status & ScriptHandle.STATUS_DONE) {
         break;
      }
   }
} catch (ObolException e) {
   System.err.println(e);
}
Listing Two

Scripts have access to this mechanism, and can invoke other scripts via the [use] metacommand, binding local symbols to input/return symbols defined by the invoked script. Unresolved input requirements are eventually forwarded to the application. Listing Three (available at http://www.ddj.com/code/) is an example of how to examine a script's input requirements; Listing Four (also available at http://www.ddj.com/code/) presents a much quicker way of setting known inputs. The approach is similar for scripts' return values, using the getResultSpecification() and getIntermediateResults() API methods.

Conclusion

The Obol protocol programming language allows for testing and experimentation when constructing and using security protocols in real systems. It provides many other features useful to the protocol programmer than what's presented here (control structures, interactivity, and use as a crypto coprocessor). Obol is also used by the GridKit project (www.nw-grid.ac.uk/) at the University of Lancaster, UK to experiment with flexible security policies [7].

Acknowledgments

Thanks to Dr. Tage Stabell-Kulø at the University of Tromsø, Norway. Also, thanks to the GridKit project at the University of Lancaster, in particular Na Xu, Gordon Blair, and Paul Grace, for their investigations into integrating Obol into a reflective middleware platform.

References

  1. [1] Ross Anderson. "The Initial Costs and Maintenance Costs of Protocols," in 13th International Workshop on Security Protocols, 2005.
  2. [2] David Lorge Parnas. "Software Aging," in Proceedings of the 16th International Conference on Software Engineering, 1994.
  3. [3] Tage Stabell-Kulø and Simone Lupetti. "Publickey Cryptography and Availability," in Proceedings of the 24th Conference on Computer Safety, Reliability and Security, 2005.
  4. [4] Simone Lupetti, Feike W. Dillema, and Tage Stabell-Kulø. "Names in Cryptographic Protocols," in Proceedings of the 4th International Workshop on Security in Information Systems, 2006.
  5. [5] Michael Burrows, Martin Abadi, and Roger Needham. "A Logic of Authentication," ACM Transactions on Computer Systems, February 1990.
  6. [6] Butler Lampson, Martin Abadi, Michael Burrows, and Edward Wobber. "Authentication In Distribued Systems: Theory and Practice," ACM Transactions on Computer Systems, November 1992.
  7. [7] Na Xu, Gordon Blair, Per Harald Myrvang, Tage Stabell-Kulø, and Paul Grace. "The Role of Reflective Middleware In Supporting Flexible Security Policies," to appear in Proceedings of NODe, 2006. DDJ

A Full Protocol Example

The Needham-Schroeder shared-key distribution algorithm in its original form has security issues, but is quite simple and easy to understand. In the traditional Alice-n-Bob notation, it is described as:

Message 1 A -> S : A,B,NA

Message 2 S -> A :NA,B,KAB, {KAB,A}KBS KAS

Message 3 A -> B : {KAB,A}KBS

Message 4 B -> A : {NB}KAB

Message 5 A -> B : {NB-1}KAB

Implementing this is not as easy as it seems, and all kinds of considerations pop up: there are only five messages, but three participants; there are multiple naming schemes—A, B, and S are both roles, identifiers, and key lookup indexes. Listings Five, Six, and Seven (available in the source code area) show Obol scripts for all three parties. The scripts for A and B show how to use default values for input requirements, and how the generate operand can be used to invoke an external Lisp interpreter for computing NB-1. To keep Obol domain-specific, there is no built-in support for general computation, so an external language is used. Currently, the Obol runtime supports the external interpreters ABCL (Armed Bear Common Lisp, armedbear.org/abcl.html) and Jython (Python in Java, jython.org).

How To Program in Obol

Obol scripts tend to follow a similar pattern, but the only real restriction are dependencies; specifically, inputs must be specified by [input] statements before being used. Any mention of "application" refers to the software using the Obol runtime or a particular script.

  1. The header:
    1. Decide which input the script needs, and specify the appropriate [input] metacommands. Remember, the script will not execute non-metacommands unless the application sets all required inputs.
    2. If the script returns any output, specify that with [returns] metacommands.
    3. Decide where the script should look for incoming messages by using the [self] metacommand, which also configures receive modes.
    4. Optionally specify the message representation format to use for constructing messages (also for cryptographic operations), by means of the [format] metacommand,

  2. Initialization of local state. This includes generation of various data, loading keys, and the like.
  3. Constructing and sending the first message, or expecting the first incoming message.
  4. The protocol proper.
  5. Termination. This phase may include setting return values or error messages.

(a)
(script "Server"
   [input portNo number]
   [returns data string]
   [self portNo default   
	   :poolmode]
   [format default]
   (receive *client *data)
   (believe data *data
     ((type string))))
     
     
(b)
(script "Client"
   [input portNo number]
   (believe data 
	      "Hello World!")
   (believe server 
	      "127.0.0.1" 
	      ((port portNo)))
  (send server data))

Here is a "Hello World" type client-server pair showing the aforementioned pattern for (a) server; (b) client.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.