Subject: Some implementor's notes

From: Greg Hudson <[email-masked]>
Date: Mon, 13 Oct 2003 13:19:19 -0400

I'm writing these notes in hopes that they will provide insight on
possible barriers to SASL's adoption.

When I created the custom Subversion protocol, I decided to use SASL
for authentication because I liked the concept and because I dislike
the properties of X.509 certificates, which (via TLS) are the only
real alternative that I know of.  I started out by implementing
ANONYMOUS and EXTERNAL myself, since those are trivial.

I figured for the real meat, I would use a library, since in an ideal
world applications have no business implementing authentication
systems.  Unfortunately, I'm finding the Cyrus library unsuitable
(I'll detail the reasons for this at the end, since it's
implementation-specific) and I can't use the gsasl library in
Subversion since it is covered by the GPL.  So, since there have been
a lot of calls for password authentication, I thought maybe I would
implement one of the shared-secret systems without stream protection;
Subversion's utility libraries already include an MD5 implementation,
so I figured I wouldn't need to introduce any complicated pieces of
code.

First, I looked into CRAM-MD5.  It doesn't authenticate the server and
it doesn't leave the window open for stream protection, but those
issues aren't critical.  I found the following sources of hidden
complexity:

  * The processing of the secret (pad to 64 bytes or digest and then
    pad to 64 bytes) is clunky and has no value in an MD5 context as
    far as I know.

  * I find it important to avoid storing passwords in clear text,
    since people often use the same password for multiple systems.  To
    accomplish this, you need an MD5 implementation which supports
    saving intermediate states.

  * The current draft mandates the use of RFC 3454, a 91-page RFC I
    don't understand and which does not look trivial to implement.
    I'm sure there are real issues with internationalized usernames
    and passwords, but the blow-up in complexity seems astounding.

Faced with these problems and a general sense of guilt at the idea of
implementing a weak system, I turned to DIGEST-MD5.  I found that
while DIGEST-MD5 is much more elegant than CRAM-MD5 in how it computes
the digests, it comes with a burdensome level of complexity which is
unrelated to its conceptual security properties.  In particular:

  * It introduces the concepts of realms, subsequent authentication,
    and authorization IDs, none of which seem to be important
    functionality for a generic shared-secret authentication scheme,
    and all of which could (I think) be handled out of band.
    Fortunately, it's not too difficult to avoid supporting those
    features.

  * Messages are composed of key-value pairs which do not obey a
    consistent syntax for the value, so parsing them is hard.  (I'm
    not convinced that Cyrus's implementation is correct, particularly
    for skipping over auth-param values.)

  * Length-counted strings would be easier to parse than quoted
    strings while remaining human-readable.

  * Implicit allowance for linear whitespace has no intrinsic value
    and renders implementations more complicated and error-prone.

  * It is not specified whether the serv-type, host, and digest-uri
    values are required.  (Cyrus treats digest-uri as required but not
    the other two, probably because it's not specified what you should
    do with an unspecified digest-uri when computing the digests.)  It
    is not made clear what security value, if any, these parameters
    have; to "detect accidental connection to the incorrect server" is
    not an important function for an authentication scheme.

  * The UTF-8 to ISO 8859-1 recoding of usernames and passwords seems
    like a very burdensome requirement to place on the protocol for
    the sake of a very implementation-specific convenience.  One can
    avoid this complexity by not supporting UTF-8, but that in itself
    is unfortunate.

Most of this complexity is there to provide wire similarity between
DIGEST-MD5 as used in SASL and in HTTP, but that's not a compelling
justification for requiring a tenfold expansion in code size over what
would be required to compute the digests and do basic parsing.

Because of this complexity, I am likely to go back to CRAM-MD5,
ignoring the RFC 3454 requirement in the current draft.  I'm not sure
what SASL can do at this point to reduce the implementation burdens,
but I have to say that I am sorely disappointed.  When one is
designing a security system, one should compromise simplicity only in
the name of security.

As promised, here are my major issues with the Cyrus SASL
implementation:

  * As I've discussed before, if you're a library invoking the SASL
    library, there's no way to ensure thread-safety while remaining
    compatible with other libraries invoking SASL.

  * The getopt interface seems to be a barrier to successfully
    documenting or internationalizing an application's configuration
    system.

  * The API does not successfully hide the complexity of the
    underlying mechanisms, such as digest-md5's realms.  (By "hide"
    here I don't mean the API shouldn't support them, but that you
    should have to go to extra effort to use them, instead of having
    to go to extra effort to ignore them.)

  * The secrets database is kept in a database format which depends on
    the build of the library.  If you go from one build to another
    (say, by upgrading versions of Red Hat) and the new build uses a
    different database, your server stops working and you get a
    cryptic error.  That seems totally unacceptable, and I wonder how
    existing users of the library are dealing with it.

  * The secrets database keeps secrets in plain text, which I find
    unacceptable due to the amount of password-sharing users do.

---

From: "Paul Leach" <[email-masked]>
Date: Tue, 14 Oct 2003 11:55:33 -0700

SASL's version of Digest has that clunky syntax so that it is possible to
share an implementation with HTTP digest. HTTP digest couldn't get cleaned
up when HTTP 1.1 was being worked on because some people claimed there were
significant deployments of an earlier version.

The "subsequent auth" feature was a request from client authors of apps
where reconnects are frequent and the desire was to make them efficient.
(POP3 clients are or used to be typical examples.)

> -----Original Message-----
> From: [email-masked] 
> [mailto:[email-masked]] On Behalf Of Alexey Melnikov
> Sent: Tuesday, October 14, 2003 3:37 AM
> To: Greg Hudson
> Cc: [email-masked]
> Subject: Re: Some implementor's notes
> 
> 
> Greg Hudson wrote:
> 
> >...
> >
> >...
> I have to disappoint you, but DIGEST-MD5 requires RFC 3454 as 
> well (at least it will when I publish a new revision)
> 
> >
> >implementing a weak system, I turned to DIGEST-MD5.  I found 
> that while 
> >DIGEST-MD5 is much more elegant than CRAM-MD5 in how it computes the 
> >digests, it comes with a burdensome level of complexity which is 
> I suggest you try to find a case that breaks stuff. It is 
> more constructive than saying that something doesn't (or may 
> not) work.
> 
> Yes. There are historical reasons why this happened.
> It was a compromise between design and something that could 
> have been implemented by one big vendor.
> It was supposed to become a replacement for another seriously 
> broken SASL mechanism NTLM.
> 
> >    values are required.
> They are required to be sent, but the receiver SHOULD (but 
> not required
> to) verify it. If the text is not clear, let me know and I 
> will try to fix it.
> 
> >  (Cyrus treats digest-uri as required but not
> See above.
> >but I have to say that I am sorely disappointed.  When one 
> is designing 
> >a security system, one should compromise simplicity only in 
> the name of 
> >security.
> >
> SASL has nothing to do with your problem (well, very little to do).
> SASL is just a framework. If you don't like mechanisms that 
> are currently available, you can write a new one and try to 
> make it deployed.
> 
> Why?
> Yes, this is a bit unfortunate, but I had exactly the same 
> problem trying to write a different SASL implementation.
> 
> >
> >    the build of the library.
> >
> Shouldn't really. Secrets are usually stored in sasldb 
> backend, the format is quite stable at this point and 
> shouldn't change very much over the time.
> 
> >  If you go from one build to another
> Alexey