BEEP: The Definitive Guide

Using SASL: CMU's Cyrus SASL Library

by Marshall T. Rose, author of BEEP: The Definitive Guide

The Simple Authentication and Security Layer (SASL) allows administrators to configure just the right amount of security for the networked applications in their environments. A previous article explained SASL; in this article, we see how to program with SASL using an open source library.

1. Introduction

In a previous article, we took a look at a "meta API" called the Simple Authentication and Security Layer (SASL). The idea behind SASL is that when you design an application protocol, you can treat the communications security technologies as loadable modules.

SASL shifts the burden of picking and choosing the technologies used for authentication, integrity checking, and privacy from you, the application writer, to the network administrator.

For example, depending on the environment, some administrators may choose to configure authentication and integrity-checking, but no privacy. As an application writer, your job isn't to make decisions like this -- instead, your job is to provide the network administrator with maximal flexibility to pick the appropriate level of security for the job at hand.

Once you decide to use SASL, your next choice is whether to roll your own SASL implementation or to use an existing library. Speaking as someone who's done both, I'll tell you that while it may be necessary -- in very constrained environments -- to write your own SASL layer, it's almost always better to use an off-the-shelf library.

In this article, we'll look at Carnegie Mellon University's (CMU) Cyrus SASL. This is the SASL library used by sendmail, OpenLDAP, and the Cyrus ACAP and IMAP servers. The native library is written in the C programming language, and it also comes with a Java interface. (In addition, for you Tcl aficionados, you can find a Tcl extension to Cyrus SASL in the beepcore.tcl project on SourceForge.)

Related Reading

BEEP: The Definitive Guide
Developing New Applications for the Internet
By Marshall T. Rose

There are two major versions of Cyrus SASL:

  • Version 1, which stabilized in August 1999; and
  • Version 2, which stabilized in March 2002.

For the rest of this article, we'll be talking about Cyrus SASLv2. Also, just to set expectations, this article doesn't give detailed API information -- it's an overview, not a reference manual, for Cyrus SASL.

All of the Cyrus SASL releases can be found here, so start by looking for a distribution named cyrus-sasl-2.*.tar.gz. On my production systems, I use Cyrus SASL v2.1.2, but on my development system, I use anonymous CVS to stay in sync with the Cyrus developers.

Once you've extracted the tar image, do the two usual things: look at the README file and then run configure --help to determine which configuration options are available. You might also want to browse doc/install.html for some tips on where to find the libraries that Cyrus SASL likes.

After configure successfully runs, it's just a make, su, make install, and we're ready to go.

2. The Ground Rules

The procedure calls that "do SASL" are pretty simple, even if the work they do is somewhat complex. However, before you actually "do SASL," you have to setup some data structures so that Cyrus SASL will interface correctly to your program and your environment. There are two of these "universal" data structures.

The first is the callback data structure. When Cyrus SASL is in the middle of doing something and it needs more information, it consults a callback. Each callback has three fields:

  • an identifier, which is a C-preprocessor symbol (e.g., SASL_CB_PASS);
  • a pointer to a procedure; and
  • a pointer to a void * that's passed to the procedure.

The parameter list for the procedure depends on the value of the identifier -- each callback has a different parameter list. (Because of the way C handles indirect procedure calls, you must be very careful to make sure that the procedure you define provides the exact parameter list expected by Cyrus SASL -- if not, there will be trouble, and there's nothing that Cyrus SASL can do about it.)

Cyrus SASL has a lot of callbacks, and although some are "generic," most are either server-only or client-only. Fortunately, you can pretty much get by with defining only two:

  • SASL_CB_LOG, which is called to write an entry to your program's logfile; and,
  • SASL_CB_GETOPT, which is called to get configuration information.

For example, if your program has its own config file, the procedure you point to in the callback should look at your program's config file for SASL-specific information.

Cyrus SASL gives you two opportunities to define your callback list. The first is when you initialize the library, and the second is whenever you establish a network connection. This leads us to the second data structure, called a context, which keeps track of the SASL state associated with a network connection, from cradle to grave.

3. Client-side SASL

The first step is to call the routine that initializes Cyrus SASL and pass it your global callback list. Cyrus SASL actually provides two initialization routines, one for client-side and the other for server-side behavior. Based on how your program is going to behave, feel free to call just one or both.

The second step is to make an outgoing connection and then create a client context for it. Now at this point your program has to do a bit of thinking about whether it should negotiate the use of TLS. (After you do SASL, it's too late to start TLS.) How you make this choice is up to you, but here are some things to consider:

  • If there's a configuration option or a command-line argument saying that you must (or not to bother), then the decision is easy.
  • If the operating system tells your program the connection is already encrypted (e.g., you're running over a VPN or using IPSEC), then there's no point in doing TLS.
  • If the server didn't advertise TLS, then the decision is easy.
  • If the server advertised a SASL mechanism that can support security (e.g., DIGEST-MD5 or KERBEROS_V4), then you can tell Cyrus SASL to require privacy instead of doing TLS.

Regardless, at this point you tell Cyrus SASL the actual and desired security level of the connection, expressed as an integer. Typical values are 0 (nothing), 1 (integrity-checking only) 56, 112, and 128. Excluding zero and one, it's easiest to think of this as the number of bits in the session key being used for privacy.

Now comes the fun part -- you call a routine that takes the SASL mechanisms advertised by the server, and it tells you:

  • which SASL mechanism to tell the server to start; and
  • the "initial" data to pass to the server, if any.

(Or, if your requirements aren't compatible with what the server offers, you'll get back an error return instead.) The key thing to understand here is the division of labor: your program is responsible for moving the bits back and forth, and Cyrus SASL is responsible for figuring out what bits are sent and interpreting whatever bits are sent back.

Although this sounds straightforward, there's a little bit of ugliness we have to digress into. Some protocols don't let the client supply initial data to the server when they ask to start a SASL mechanism. For example, SMTP allows initial data, but IMAP doesn't. When you call the routine to start the client negotiation, you tell Cyrus SASL whether initial data is allowed.

Let's look at an example. Say you're writing an SMTP client and you want to do SASL stuff. When you connect to an SMTP server:

S: 220 ESMTP server ready
S: yabba, dabba, doo!
S: 250 HELP

The server ("S:") will identify itself with a 220 greeting, your program, the client ("C:"), sends an EHLO command to find out what services are offered, and the server says it supports SASL with four mechanisms (AUTH ...), TLS (STARTTLS), and the help command.

Now your program has to decide whether to do TLS, since the server advertised it. If so, your program tells the server to start TLS, and ultimately your program gets back another 220 greeting, and sends another EHLO. (Obviously, it's a bit more complicated than this -- check out RFC 3207 for all the details.)

Regardless of whether you're doing TLS, your program creates a client context for Cyrus SASL, and sets the actual and desired security properties for that context. Next, your program strips the 250-AUTH from the server's response and tells Cyrus SASL that you're ready to do SASL.

The routine that decides what your program should tell the server is pretty complicated. First, it has to determine which available SASL mechanisms (termed "plug-ins") meet your security requirements and are supported by the server. Then it tries to initialize them in order of preference. During this process, the plug-in may need additional information from your program (e.g., a username or a password). This is where one or more client-side callbacks are invoked. This is also where you'll find the most complexity in the Cyrus SASL client-side interface.

Pages: 1, 2

Next Pagearrow